本博文由 youngpan1101 出品,转载请注明出处。
文章链接:https://blog.csdn.net/youngpan1101/article/details/105503352
作者: 宋洋鹏(youngpan1101)
邮箱: yangpeng_song@163.com
ps:该笔记是基于《C++设计模式 [李建忠]》的学习笔记 [视频链接] [源码和PPT资料下载]
动机
- 软件构建中,对象使用的算法种类多样,且具有常变属性,如果将这些算法都编码到对象中,将会使得对象变得异常复杂,有时支持不使用的算法也是一个性能负担;
- 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
代码示例
- strategy1.cpp
enum TaxBase {
CN_Tax,
US_Tax,
DE_Tax,
FR_Tax //更改
};
class SalesOrder{
TaxBase tax;
public:
double CalculateTax(){
//...
if (tax == CN_Tax){
//CN***********
}
else if (tax == US_Tax){
//US***********
}
else if (tax == DE_Tax){
//DE***********
}
else if (tax == FR_Tax){ //更改:违背了 开闭原则, 对扩展开放,对更改关闭
//...
}
//....
}
};
- strategy2.cpp 【更为合适的实现】
class TaxStrategy{
public:
virtual double Calculate(const Context& context)=0;
virtual ~TaxStrategy(){} // 虚析构函数,否则多态 delete 会有问题
};
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->NewStrategy(); //工厂模式
}
~SalesOrder(){
delete this->strategy;
}
public double CalculateTax(){
//...
Context context();
double val = strategy->Calculate(context); //多态调用
//...
}
};
要点总结
- 需要从时间轴上来考虑软件构建过程,比如说上面示例中的 Tax 会在将来支持不同的国家
- 基类务必要有虚析构函数,否则多态 delete 会有问题
- 用指针来是实现多态的变量
- 上面示例,后者方法的好处:如果增加一个 France Tax 的处理,只需要扩展一个 class FRTax, 而 class SalesOrder 没有发生修改,遵循开放封闭原则
- 面向对象中的复用:是编译之后,二进制文件的复用
- 在 if-else 后面添加代码,往往会打破原有的代码逻辑,引入新的 bug
- 策略模式:定义一系列算法,把他们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)
- Strategy 及其子类为组件提供了一系列可重用的算法,从而使类型在运行时方便地根据需要在各个算法之间进行切换
- Strategy 模式提供了用条件判断语句之外的另一种选择,消除条件判断语句(结构化,分而治之的写法),就是在解耦,含有许多条件判断语句的代码通常都需要 Strategy 模式
- 如果 Strategy 对象没有实例变量,那么各个上下文可以共享同一个 Strategy 对象,从而节省对象开销