我先抛出代码给大家看看。
enum TaxBase{
CN_Tax,
US_Tax,
DE_Tax
};
我们定义一个枚举类型,大家可以看出,这是一个关于税种的枚举。现在我们的业务需求就是要实现一个可以计算税收金额的程序(类)。
class SalesOrder{
TaxBase tax;
public:
double CaculateTax(){
if (tax == CN_Tax){
//计算中国的税率
}
else if (tax == US_Tax){
//计算美国的税率
}
else if (tax == DE_Tax) {
//计算德国的税率
}
//........
}
};
我们在SalesOrder里的CaculateTax方法来计算税额,通过if-else语句或者是switch开关语句来判断用哪个国家的税率计算税额。我们可以看到SalesOrder依赖于TaxBase。现在由于需求变更,需要增加一个国家的税额计算,比如说法国。然后现在我们至少要更改两个地方,第一处是枚举类型TaxBase需要增加FR_Tax这个枚举,然后就是CaculateTax方法里的判断语句那儿需要再增加一个判断。
在设计模式里有八大原则,其中一条就说明了我们设计的时候,要遵循对修改关闭,对扩展开放的原则。上面那种方法很显然是违背了这个原则的,有很多更改的地方。我们试着换一种方法,看代码:
//抽象基类
class TaxStrategy {
virtual double CaculateTax() = 0;
virtual ~TaxStrategy(){}
};
//子类
class CNTax : public TaxStrategy {
virtual double CaculateTax(){
//计算中国的税额
}
};
//子类
class USTax : public TaxStrategy {
virtual double CaculateTax(){
//计算美国的税额
}
};
//子类
class DETax : public TaxStrategy {
virtual double CaculateTax(){
//计算德国的税额
}
};
现在我们把计算税额抽象出来,叫TaxStrategy,这是所有计算税额的基类,我们这里实现了CNTax,USTax,DETax。现在当我们需求增加的时候,比如说要增加法国的,然后就可以直接写一个FRTax类继承TaxStrategy就可以了,这就是扩展。然后我们的SalesOrder就可以这么写。
class SalesOrder {
TaxStrategy *taxStrategy;
public:
SalesOrder(TaxStrategy *strategy){
taxStrategy = strategy;
//这里可以运用工厂模式优化.....
}
double CaculateTax(){
//......
//这里通常有个上下文对象,联系TaxStrategy和SalesOrder
double val = taxStrategy->CaculateTax()
//......
}
};
这样一来,税额的计算与以哪个国家的税率计算从静态绑定变成了动态绑定。这里我们也来分析一下什么是稳定的,什么是不稳定的。最初SalesOrder的是不稳定的,它依赖于TaxBase,当业务需求变更的时候,TaxBase是不稳定的,比如说上面的增加法国税率的计算,就需要改变TaxBase和SalesOrder,但现在我们把计算税率这个算法抽象出来为TaxStrategy,那么它就变成稳定的了,然后让SalesOrder依赖于TaxStrategy,那么这两个都是稳定的了,然后不稳定地方是TaxStrategy的子类,然后通过多态把稳定的SalesOrder和TaxStrategy的子类动态绑定起来。这个就是策略模式,很好的解释了“对修改关闭,对扩展开放”这个原则
好了,今天就到这里,谢谢大家的阅读。
|