在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂,而且有时候支持不使用的算法也是一个性能负担。
如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
这里提到一个策略模式,举个例子来说吧,这是对笔者项目的一种思考:
还是远控软件:
我们来看step10和step12。由于采用的是完成端口模型,这里得先在主对话框中的函数走一趟,然后去相应的子对话框。目前的实现方法呢,是Completion Key中有一个字段叫DlgID,也就是在主对话框中设计了一个函数,里边有一个switch结构,用于判断Completion Key中的DlgID到底是什么,然后再去相应的对话框下处理数据。
这样做的问题是什么呢?你既然用了Switch,那就必然要把每一个功能的逻辑写一遍。第一,代码非常冗余;第二,在该函数中支持了不必要的算法代码。
既然这一块的代码要经常改变(针对不同的具体功能)。那我干脆在Completion Key中设置一个函数指针字段,用来放不同套接字所对应的Handle函数,直接把数据丢到处理函数中去。实现Handle函数和主对话框处理函数的解绑。代码也会更加简洁。
当然上述只是笔者个人的自省。如果这样发出来没有科普价值,给大家分享一下李建忠老师的例子:
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){ //更改
//...
}
//....
}
};
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); //多态调用
//...
}
};
给大家解释一下。
整体来说呢,是一个计算税的需求。要对不同国家的税进行计算,但计算方法不一样。
第一个例子是没有使用策略模式,把所有的税计算过程都写进来了,当需要更新的时候,再加一个if分支就好了,一点都不优雅。
第二个例子是用了策略模式的。设计一个抽象类Tax,CNTax、ENTax等都继承自Tax,并重写Calculate函数,这样使用的时候我new一个具体对象(Tax,里氏替换原则)出来,直接调用Calculate函数就好,我不用操心它到底是哪个国家的。