C++设计模式
整理自李建忠老师的《C++设计模式》视频教程
“组件协作”模式:
- 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。
- 典型模式
- Template Method
- Strategy
- Observer / Event
04_Strategy策略模式(组件协作模式)
1.动机(Motivation)
- 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
- 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
2.代码
2.1代码1
注意:要动态的看软件结构的设计
enum TaxBase {
CN_Tax, //中国的税率
US_Tax, //美国的税率
DE_Tax, //德国的税率
FR_Tax //法国的... //更改 - 新增的
....
};
class SalesOrder{
TaxBase tax;
public:
// 计算税
double CalculateTax(){
//...
/*当遇到
if else ...
switch case ...
当遇到扩展时....
就可以使用:Strategy策略模式+工厂模式
*/
if (tax == CN_Tax){
//CN***********
}
else if (tax == US_Tax){
//US***********
}
else if (tax == DE_Tax){
//DE***********
}
else if (tax == FR_Tax){ //更改 - 新增的
//...
}
//....
}
};
/*
上面的代码违背了"开闭原则":
第5行 第25行...
带来很大的复用性的负担:重新更改 重新编译 重新部署...
开闭原则":对扩展开放 对更改封闭
类模块要尽可能的用扩展的方式去支持未来的变化
而不是直接去更改原来的代码来应对未来的变化
*/
上面的代码违背了"开闭原则":
第5行 第25行…
带来很大的复用性的负担:重新更改 重新编译 重新部署…
开闭原则":对扩展开放 对更改封闭
类模块要尽可能的用扩展的方式去支持未来的变化
而不是直接去更改原来的代码来应对未来的变化
当遇到 if else … 、switch case … 后续会扩展时…,就可以使用:Strategy策略模式+工厂模式。
当 if else … 、switch case … 绝对稳定 不会再变化时(比如一周七天),就可以不使用Strategy策略模式。
2.2代码2(应用了Strategy策略模式后)
开闭原则
复用性:说的是二进制意义上,编译后的编译单位的复用性…
二进制意义的复用性
//-----------------------------------------------------//
//基类
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{}稳定,不需要更改了
class SalesOrder{
private:
//多态指针(多态时最好用指针 尽量不用引用 因为引用在多态时有些问题)
TaxStrategy* strategy = nullptr;
public:
// 工厂模式!!!
SalesOrder(StrategyFactory* strategyFactory){
this->strategy = strategyFactory->NewStrategy();
}
~SalesOrder(){
if(this->strategy != nullptr){
delete this->strategy;
this->strategy = nullptr;
}
}
public:
double CalculateTax(){
//...构建算法上下文参数
Context context();
double val =
strategy->Calculate(context); //多态调用
//...
}
};
//-----------------------------------------------------//
3.模式定义
定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。——《设计模式》 GoF
4.结构(structure)-UML
5.要点总结
- Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。
- Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
- 如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象(单例),从而节省对象开销。