参考资料:
https://www.bilibili.com/video/av24176315/?p=4
动机
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使得对象变得异常复杂,而且有时候支持不使用的算法 也是一种性能负担.
实例
考虑税法计算程序,不同国家的税法计算方式是不同的,如果构建一个税法计算的类,支持不同国家的税法计算.
不使用设计模式
enum TaxBase{
CN_Tax;
US_Tax;
DE_Tax;
};
class SalesOrder{
TaxBase tax_;
public:
double CalculateTax(){
if(tax_==CN_Tax){
//....CN_Tax
}
else if(tax_==US_Tax){
//....US_Tax
}
else if(tax_==DE_Tax){
//DE_Tax
}
}
};
静态看这个问题,这么设计是没有问题,但是如果增加了对其他国家的支持的话,怎么改动???
改动量还是比较大的.需要增加枚举类型,增加if else 语句,这样就违背了设计原则,“对扩展开放,对更改封闭”.
重构到设计模式
首先定义了一个基类TaxStrategy,里面定义了一个纯虚函数Calculte,然后定义了不同国家的税法类,去继承TaxStratety.
将原来的一个个算法变成了TaxStrategy的子类.
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{
private:
TaxStrategy* taxstrategy_;
public:
SalesOrder(StrategyFactory* strategyFactory){
this->taxstrategy_=strategyFactory->NewStrategy();
}
~SalesOrder(){
delete this->taxstrategy_;
}
double CalculateTax(){
//...
Context context(); //算法上下文
double val=strategy_->Calculate(context);
//..
}
};
这样的话,如果添加其他国家的税法,只需要添加一个类去继承TaxStrategy.
模式定义
定义一系列算法,把他们一个个封装起来,并且使他们相互替换(变化).该模式可独立于使用它的客户程序(稳定)而变换(扩展,子类化).
类图
其中,Context就是例子中的SalesOrder类.
要点总结
- Strategy及其子类为组件提供了一系列可重用的算法,从而使得类型在运行时方便地根据需要在各个算法之间进行切换.
- Strategy模式提供了除if-else语句之外的其他选择.消除条件判断语句,就是在解耦和,含有多个if else语句的指令通常需要Strategy模式