策略模式
简单来说就是不同的子类调用相同的函数名,执行不同的代码段(通过this指针类型确定要执行的函数)
策略模式往往用于解决违反开闭原则的代码,为if else提供了另一种选择。
也就是说,出现if else就可以考虑用策略模式了,如果if else里的动作是针对的不同类型,那90%就应该用策略模式。
假如我们需要计算不同国家的税费,一般是通过枚举来实现:
enum TaxBase { // 不同的国家有不同的算法
CN_Tax,
US_Tax,
DE_Tax,
FR_Tax //更改
};
class SalesOrder{
TaxBase tax;
public:
// 设计模式大忌,不要用if else 去处理不同的类
// 因为新增或删除一个类,if else就得更改,
// 违反了开闭原则:对扩展开放,对修改关闭(新增一个类不用更改其他代码)
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);
//...
}
};
策略模式是一种关联性模式,针对不同的对象,采用不同的方法,其类图如下:
tip:其实策略模式还有个附带的价值,回到第一段代码,即使我们主要的只计算中国和美国的税费,if else会把所有国家的类型都判断一遍,执行效率低下,而策略模式就解决了这个问题。