以下内容均来自GeekBand极客班C++ 设计模式课程(李建忠老师主讲)
完整代码见;https://download.csdn.net/download/qq_41605114/18881800
Strategy
“组件协作”模式:
现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作模式”通过晚绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。
典型模式:
Template Method
Strategy
Observer/Event
动机(Motivation)
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担
《设计模式》GOF定义:
“定义一系列算法,把它们一个个封装起来,并且时它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)”
蓝色为稳定部分,橘黄色为变化部分
Context 和 Strategy 为UML类图中的聚合关系
结构化编程示例
现在有一套税收计算的算法如下:
enum TaxBase{
CN_Tax,
US_Tax,
DE_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*******
}
//如果需要增加,那么此处要 更改
//......
}
};
那么以发展的眼光看问题,我们会发现,如果未来要增加其他国家的税收计算,我们需要在代码中更改,不断要更改枚举量,而且还有更改算法,不符合开放封闭原则(对扩展开放,对更改关闭)
而其中的if else部分,也散发出了马丁福勒所说的bad smell,非常典型的结构化编程思维方式的产物。.
当看到if else或者switch语句的时候,就要考虑是否能够使用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 SalesOrder类
class SalesOrder{
private:
TaxStrategy * strategy;
public:
SalesOrder(strategyFactory * strategyFactory){
this->strategy = strategyFactory->NewStrategy();
}
~SalesOrder(){
delete this->strategy;
}
double CalculateTax(){
//....
Context context();
double val =
strategy->Calculate(context());//多态调用
//....
}
};
显然,此处的SalesOrder类中包含有TaxStrategy的指针,后续直接使用多态进行调用即可。
现在回头理解代码可以发现,结构化编程中,如果需要增加一部分内容,显然我们需要更改很多地方,后期这些地方都要跟着进行测试
但是如果使用策略模式,我们需要增加其他国家的税收情况时,只需要增加一个类,继承于TaxStrategy类即可。显然策略模式符合开放封闭原则。
要点总结
1,Strategy 以及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地更具需要在各个算法之间进行切换。
2,Strategy模式 提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
3,如果Strategy对象 没有实例变量,那么各个上下文可以共享同样一个Strategy对象,从而节省对象开销。