1. “组件协作”模式
- 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。
- 典型模式
- Template Method
- Strategy
- Observer / Event
2. Strategy 策略模式
2.1 动机(Motivation)
- 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
- 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
2.2 模式定义
定义一系列算法,把它们一个个封装起来(ps:每个算法一个具体类),并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子变化)。
——《设计模式》 GoF
2.3 实例代码
2.3.1 strategy1
// 税率类
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) { // 更改,条件判断语句中增加对法国税率的分支
// ...
}
// ....
}
};
2.3.2 strategy2
// 税率基类
class TaxStrategy {
public:
virtual double Calculate(const Context& context)=0; // 纯虚函数
virtual ~TaxStrategy() {} // 基类的析构函数要声明成virtual
};
// 中国税率,继承基类,重写虚函数
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); // 多态调用
// ...
}
};
2.4 结构(Structure)
2.5 要点总结
- Strategy及其子类为组件提供了一系列可重用的算法(ps:实例中的各个具体类),从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。
- Strategy模式提供了用
条件判断语句
以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。 - 如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。