Strategy 策略模式
要解决的问题:
在软件按的构建过程中, 一些对象使用的方法可能多种多样, 经常会出现变动, 如果将这个方法都编码到对象方法中, 将会高频率的修改对象方法, 使其变得异常复杂, 同时也破坏了代码尽量不去变动的准则, 并且有时候支持不会去使用的一些方法也是一个性能负担
模式定义:
定义一系列算法, 将它们一个个封装起来, 并且使它们可互相替(变化). 该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展, 子类化)
举例
当要实现一个计算税务的需求时, 没有进行优化前的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| enum TaxBase { CN_Tax, US_Tax, DE_Tax, FR_Tax };
class SalesOrder{ TaxBase tax; public: double CalculateTax(){ if (tax == CN_Tax){ } else if (tax == US_Tax){ } else if (tax == DE_Tax){ } else if (tax == FR_Tax){ }
} };
|
可以看到, 如果要新增国家的话, 那么就要在原来的代码上进行改动, 通过增加 else if
的形式进行源码级改动, 如果这种改动逐渐增多了之后, 将会使得可维护性大大降低, 而且一次增加将会影响大量的代码,
使用 Strategy 策略模式进行重构
考虑将计算税收的方法抽象出来, 通过继承的方式来对可能会增加的税收方式进行扩展, 这样只需要将不同计算税收的指针赋给父类的指针, 就可以利用多态来实现不同国家的税收计算
类结构
重构代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| 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->NewStrategy(); } ~SalesOrder(){ delete this->strategy; }
public double CalculateTax(){ Context context(); double val = strategy->Calculate(context); } };
|
要点总结
- Strategy 及其子类为组件提供了一系列可重用的方法, 从而使得类型在运行时方便地根据需要在各个算法之间进行切换
- Strategy 模式提供了用条件判断语句外的另一种选择, 消除条件判断语句, 就是在解耦合. 含有许多条判断语句的代码通常都需要 Strategy 模式
- 如果 Strategy 对象没有实例变量, 那么各个上下文可以共享一个 Strategy 对象, 从而节省对象开销