1.模式定义

     定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。
                                                                                                                                                           -《设计模式》GoF

    这个定义很抽象,看不懂没关系,下面我们将以实例说明策略模式的思想。

    假设我们的软件系统中,需要计算应纳税额,由于不同国家税法计算公式差别很大,因此需要分别处理。

2.初级的代码

    没有设计模式思维的人,会自然而然的想到一个方法:枚举+判断。首先,枚举出需要实现哪些国家的税法。

enum TaxBase {
	CN_Tax,
	US_Tax,
	DE_Tax
};

    然后,通过条件判断语句(if语句或swith语句),返回相应的税额。其中,每个判断语句中分别实现不同国家税法。

class SalesOrder {
private:
	TaxBase tax;
public:
	double CalculateTax()
	{
		if (tax == CN_Tax)
		{
		}
		else if(tax == US_Tax)
		{
		}
		else if(tax == DE_Tax)
		{
		}
	}
};

    这种实现方案初看起来没有问题,但是当考虑到业务变化时,就会发现它的不足之处。

    假设我们的业务扩张到了法国,那么需要增加法国税额计算。在上述设计方案下,我们需要增加一个枚举类型FR_Tax,增加一个条件判断else if (tax == FR_Tax) {},并在判断语句中计算法国的税额。然后代码需要重新编译,重新测试,重新部署。

     上述方法明显违背了软件设计原则中的开闭原则,即对扩展开放,对更改封闭

3.高级的代码

    有设计模式思维的人,就会考虑用策略模式实现上述需求。首先,定义一个基类。

class TaxStrategy
{
public:
	virtual double Calculate(const Context& context)=0;
	virtual ~TaxStrategy() {}
};

    注:纯虚方法有=0的标记,必须使用虚析构函数,否则delete会出问题。

    然后,不同国家继承上述基类,实现税额的计算。

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 SalesOrder
{
private:
	TaxStrategy * strategy;            //基类指针
public:
	SalesOrder(StrategyFactory *strategyFactory)   //用工厂方法生成对象指针
	{
		strategy = strategyFactory->NewStrategy();	
	}
	~SalesOrder()
	{
		delete strategy;
	}
	double CalculateTax()
	{
		Context context;       //上下文
		double val = strategy->Calculate(context);  //多态调用
		return val;
	}
};

    现在,同样考虑业务扩展的情况,需要增加法国税额的计算,现在我们只需要增加一个新类FRTax,SalesOrder 等其它类不再需要变化。用扩展的方式支持未来的变化,而不是修改源代码的方式,这种方案遵循了开闭原则,增强了软件的复用性。

class FRTax :public TaxStrategy {
public:
	virtual double Calculate(const Context& context) {}
};

4.总结

    策略模式下,基类及其子类为组件提供了一系列可以重用的算法,从而在运行时方便地根据需要在各个算法之间切换。

    策略模式提供了用条件判断语句之外的另一种选择,消除条件判断语句,就是在解耦合。含有多个条件判断语句的代码通常都需要考虑策略模式。

               策略模式(Strategy )       

 

 

 

 

相关文章: