定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化),该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都硬编码到对象中,将会使对象变得异常复杂;而且有时候支持不适用的算法也是一个性能负担(代码段过长)
如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
这种做法很简单:
enum TaxBase{
CN_Tax, // 国内税
US_Tax, // 美国税
DE_Tax // 德国税
/*
如果需要增加,需要在这里继续枚举的定义....
JP_Tax,
FR_Tax
*/
};
class SalesOrder{
private:
TaxBase tax;
public:
double calculateTax(){
//...
if(tax == CN_Tax){
// CN*****
}
else if(tax == US_Tax){
// US*****
}
else if(tax == DE_Tax){
// DE*****
}
// 这里需要增加拓展国家税的计算方式
}
};
class TaxStrategy {
public:
virtual double calculateTax() = 0;
virtual ~TaxStrategy();
};
class CNTax: public TaxStrategy{
public:
double calculateTax() override {
// 国内税计算
}
};
class USTax: public TaxStrategy{
public:
double calculateTax() override {
// 美国税计算
}
};
class DETax: public TaxStrategy{
public:
double calculateTax() override {
// 德国税计算
}
};
class JPTax: public TaxStrategy{
public:
double calculateTax() override {
// 日本税计算
}
};
class SalesOrder{
private:
TaxStrategy *taxStrategy; // 基类指针
public:
SalesOrder(TaxStrategy *_taxStrategy): taxStrategy(_taxStrategy){
}
virtual ~SalesOrder(){
delete taxStrategy;
taxStrategy = nullptr;
}
double calculate(){
// ...
// 还是动态绑定通过虚函数来调用实际的传入对象的calculateTax方法
double val = taxStrategy->calculateTax();
// ...
return val;
}
};
通过这个UML图可以看到TaxStrategy和SalesOrder是相对稳定的,而不稳定的是TaxStrategy的子类
Strategy及其子类为组件提供了一系列的可重用的算法,从而可以使得类型在运行时方便地根据需要再各个算法之间进行切换
Strategy模式提供了用条件判断语句意外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式
如果Strategy对象没有实例化变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。