Template Method
1.结构化软件设计流程
class Library
{
public:
void Step1(){ ... }
void Step3(){ ... }
void Step5(){ ... }
}
class Application
{
public:
bool Step2(){ ... }
void Step4(){ ... }
}
int main(){
Library Lib();
Application app();
Lib.Step1();
if(app.Step2()){
Lib.Step3();
}
for(int i = 0; i < 4 ; i++){
app.Step4(); // 支持变化 == > 虚函数的多态调用
}
Lib.Step5();
}
2.面向对象软件设计流程
库代码
// 程序库开发人员
class Library
{
public:
// 稳定的template method
void Run(){
Step1();
if(Step2()){ // 支持变化 == > 虚函数的多态调用
Step3();
}
for(int i = 0; i < 4 ; i++){
Step4(); // 支持变化 == > 虚函数的多态调用
}
Step5();
}
virtual ~Library(){ }
}
protected:
void Step1() { ... } // 稳定
void Step3() { ... } // 稳定
void Step5() { ... } // 稳定
vitural bool Step2() { ... } = 0 // 子类重写实现
vitural void Step4() { ... } = 0 // 子类重写实现
应用代码
// 应用程序开发人员
class Application : public Library
{
protected:
vitural bool Step2() { ... } // 子类重写实现
vitural void Step4() { ... } // 子类重写实现
}
main函数
int main()
{
Library* plib = new Application ();
plib->run();
delete plib;
}
3.模式定义
定义一个操作中的算法骨架(稳定),而将一些步骤延迟(变化)到子类种。template method使得子类可以不改变(复用)一个算法的结构即可以重定义(override重写)该算法的某些特定步骤。
4.结构
5.要点总结
策略模式
1.动机
2.策略1
可能会在以后增加其他国家的税额计算需要增加枚举类型, 违反开放封闭原则,违背了复用性,尽可能用扩展的方式解决问题
// 不同国家税额计算
enum TaxBase{
CN_Tax;
US_Tax;
DE_Tax;
// 增加
}
class SalesOrder{
private:
TaxBase tax;
public:
// ...
if(tax == CN_Tax){
//CN...
}else if(tax == US_Tax){
//US...
}else if(tax == US_Tax){
//DE...
} // 增加 else if(...)
//...
}
3.策略2
遵循了开放封闭原则
class TaxStrategy {
public:
virtual double Calculate(const Context& context) = 0;
virtual ~TaxStrategy() {} // 虚析构函数
};
class CNTax : public TaxStrategy {
public:
virtual double Calculate(const Context& context) {
// ...
}
};
class USTax : public TaxStrategy {
public:
virtual double Calculate(const Context& context) {
// ...
}
};
class DETax : public TaxStrategy {
public:
virtual double Calculate(const Context& context) {
// ...
}
};
// 增加法国的计算支持
class FRTax: public TaxStrategy {
public:
virtual double Calculate(const Context& context) {
// ...
}
};
class SalesOrder {
private:
TaxStrategy* strategy;
public:
SalesOrder(StrategyFactory* strategyFactory) {
this->strategy = strategyFactory->NewStragety(); // 工厂模式
}
~SalesOrder() {
delete this->strategy;
}
double CalculateTax() {
// ...
Context context;
double val = strategy->Calculate(context); // 多态调用
// ...
}
};
4.模式定义
5.结构
6.总结
观察者模式
1.动机
代码1
紧耦合,违法依赖倒置原则:高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)
class FileSplitter1 {
private:
string my_filePath;
int m_fileNumber;
// 增加文件进度条
// 功能: 通知控件
ProgressBar* m_progressBar; // 具体的通知控件
public:
FileSplitter1(const string& filePath, int fileNumber, ProgressBar* progressBar):
my_filePath(filePath),m_fileNumber(fileNumber), m_progressBar(progressBar){}
void split() {
// 1.读取大文件
// 2. 分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++) {
if (m_progressBar != nullptr) {
m_progressBar->set_value((i + 1) / m_fileNumber);
}
}
}
};
class MainForm : public Form {
private:
TextBox* txtFilePath;
TextBox* txtFIleNumber;
ProgressBar* m_progressBar;
public:
void Button1_Click() {
string filePath = txtFilePath->getPath();
int number = atoi(txtFIleNumber->getText().c_str());
FileSplitter1 splitter(filePath, number, m_progressBar);
splitter.split();
}
};
代码2
松耦合,符合依赖倒置原则
class FileSplitter2 {
private:
string my_filePath;
int m_fileNumber;
// 增加文件进度条
// 功能: 通知控件
IProgress* m_iprogress; // 抽象的通知机制
// List<IProgress*> m_iProgressVector; // 抽象通知机制,支持多个观察值
public:
FileSplitter2(const string& filePath, int fileNumber, IProgress* iprogress) :
my_filePath(filePath), m_fileNumber(fileNumber), m_iprogress(iprogress) {}
// void add_IProgress(IProgress* iprogress)
// void remove_IProgress(IProgress* iprogress)
void split() {
// 1.读取大文件
// 2. 分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++) {
if (m_iprogress != nullptr) {
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;
m_iprogress->set_value(progressValue);
}
}
}
};
class MainForm : public Form, public IProgress{
private:
TextBox* txtFilePath;
TextBox* txtFIleNumber;
ProgressBar* progressBar;
public:
void Button1_Click() {
string filePath = txtFilePath->getPath();
int number = atoi(txtFIleNumber->getText().c_str());
FileSplitter2 splitter(filePath, number, this);
splitter.split();
}
virtual void DoProgress(float value) {
progressBar->set_value(value);
}
};
class IProgress {
public:
virtual void DoProgress(float value)= 0;
virtual ~IProgress();
};