Strategy 策略模式
组件协作模式通过晚绑定,来实现框架与应用程序之间的松耦合。是框架和引用程序协作常用的。
动机
某些对象使用的算法可能多种多样,经常改变,将这些算法都编码到对象中,使对象变得异常复杂,而且有时支持不适用的算法也是一种性能负担。想要在运行时根据需要透明地更改对象的算法,就要将算法与对象本身解耦,从而避免上述问题。
定义
定义一系列算法,把它们一个个封装起来,并且它们可以相互替换(变化),该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。
示例代码
enum TaxBase {
CN_Tax,
USA_Tax
};
class SalesOrder {
private:
TaxBase tax;
public:
double CalculateTax() {
// ...
if (tax == CN_Tax) {
// CN_...
} else if (tax == USA_Tax) {
// USA...
}
}
};
现有上面的示例代码,有一个 SalesOrder 类来计算税收,税现在有 CN_Tax 和 USA_Tax 类两种,用枚举表示,这里实现就根据 tax 的类型类做条件表达式的判读。 这样的代码还是在日常开发中蛮常见的,但是这样的代码有一个问题,就是当有需求变化时,我们即需要修改枚举类型,还要修改类的源代码。例如现在需要增加一个税收计算种类 FR_Tax,就需要将代码改成下面的形式:
enum TaxBase {
CN_Tax,
USA_Tax,
FR_Tax // 新增代码
};
class SalesOrder {
private:
TaxBase tax;
public:
double CalculateTax() {
// ...
if (tax == CN_Tax) {
// CN_...
} else if (tax == USA_Tax) {
// USA...
} else if (tax == FR_Tax) { // 新增代码
// FR...
}
}
};
其实上面这种方式就违背了开闭原则,即对修改封闭,对扩展开放。这种情况下,使用策略模式就是由上面的定义,将类型一个个封装起来:
class TaxStrategy {
public:
virtual double Caculate(const Context& context) = 0;
virtual ~TaxStrategy(){}
};
class CNTax : public TaxStrategy {
public:
virtual double Caculate(const Context& context) {
// ...
}
};
class USATax : public TaxStrategy {
public:
virtual double Caculate(const Context& context) {
// ...
}
}
class SalesOrder {
private:
TaxStrategy* strategy; // 使用指针实现多态
public:
SalesOrder(strategyFactory* strategyFactory) { // 工厂方法来生成对应子类
this->strategy = strategyFactory->NewStrategy();
}
~SalesOrder() {
delete this->strategy;
}
double CalculateTax() {
// ...
Context context;
double val = strategy->Caculate(context); // 多态调用
}
};
这个时候我们如果再想扩展 FR_Tax 类型则可以在上述代码的基础上,增加一个 TaxStrategy 的 FRTax 的子类(以及相应的工厂方法的子类)即可,无须再修改 SalesOrder 类的代码了。这里使用了工厂方法来生成子类对象,这部分不是本模式的重点,后面会详细介绍工厂方法。
class FRTax : public TaxStrategy {
public:
virtual double Caculate(const Context& context) {
// ...
}
}
上述的方式就是 Strategy 策略模式的内容了。
结构图
总结
- Strategy 策略模式及其子类为组件提供了一系列可重用的算法,从而是的类型在运行时方便地根据需要在各算法间进行切换。
- 提供了条件判断语句之外的另一种选择。上面的例子可以看出,消除条件判断表达式就是在解耦合,含多个条件判断语句的代码通常都需要 stategy 模式。
- 如果 Stategy 对象没有实例变量,上下文可以共享同一个对象,能节省对象开销。
其他设计模式汇总:
[设计模式] —— 设计模式的介绍及分类