第4节 策略模式

一、 策略模式动机

  1. 软件构建中,某些对象算法可能多种多样,经常改变,如果将它们都编码到对象中,会使得对象非常复杂,有时支持不适用的算法也会造成性能负担;
  2. 如何在运行时透明地更改对象的算法,将算法与对象本身解耦,从而避免上述问题?

二、策略模式定义( GOF定义)

定义一系列算法,把他们一个个封装起来,并且使他们可互相替换(变化)。该模式使得算法可独立于使用他们的客户程序(稳定)而变化.

三、代码示例

3.1 重构前代码

#include <stdio.h>

enum TaxBase           // 税种的枚举体
{
    CN_Tax = 0,
    US_Tax = 1,
    DE_Tax = 2
};

class SalesOrder
{
public:
    SalesOrder(TaxBase tax) { this->tax = tax; }
    ~SalesOrder() {}
public:
    double CalculateTax()
    {   // 根据税种类不同,计算税额,不同国家算法不同
	if (tax == CN_Tax) {}       // 情况1...
	else if (tax == US_Tax) {}  // 情况2...
	else if (tax == DE_Tax) {}  // 情况3...
	return 0;
    }
private:
    TaxBase tax;
};

int main()
{
    SalesOrder sales_order(TaxBase::CN_Tax);
    sales_order.CalculateTax();
    renturn 0;
}

3.2 问题思考

程序咋一看没什么问题,但是否考虑到程序的后续可扩展性?比如增加一些国家(枚举体),也会增加相应的算法;
违背原则:多扩展开放、对修改封闭. 本示例代码中,如将来再实现其它国家税率计算的扩展,doubleCalculateTax()的代码就需要跟着相应变化.

3.3 重构后代码

#include <stdio.h>

// 定义基类,抽象税率计算统一的格式
class TaxStrategy {
public:
    virtual double CalculateTax(const Context& contex) = 0;  // 纯虚方法
    virtual ~TaxStrategy() {}                                // 良好的习惯,基类析构都写成虚函数
};

// 添加扩展1:中国税率计算类
class CNTax :public TaxStrategy {
public:
    virtual double CalculateTax(const Context& contex) {     // 实现接口类的纯虚函数
	// Override:实现China的算法
	return 0;
    }
};

// 添加扩展2:美国税率计算类
class USTax :public TaxStrategy {
public:
    virtual double CalculateTax(const Context& contex) {     // 实现接口类的纯虚函数
	//  Override:实现US的算法 
	return 0;
    }
};

// 添加扩展3:德国税率计算类
class DETax :public TaxStrategy {
public:
    virtual double CalculateTax(const Context& contex) {     // 实现接口类的纯虚函数
	//  Override:实现DE的算法
	return 0;
    }
};

// 这里,还可以添加任何扩展

// 即使增加了国家,SalesOrder类也不需要发生任何变化
class SalesOrder
{
public:
    SalesOrder(StrategyFactory* strategyFactory){
		this->strategy = strategyFactory->NewStrategy();
    }
    ~SalesOrder() { delete this->strategy; }
public:
    double CalculateTax()
    {
	Context contex;
	double val = strategy->CalculateTax(contex);
	return val;
    }
private:
    TaxStrategy* strategy;          // 税率策略,这是一个多态指针,如果放一个对象就没有多态性了
};

// 工厂类模式将再后面的章节讲解,这里暂时先认为它是一个产生抽象对象的工具
class StrategyFactory
{
public:
    StrategyFactory()  {}
    ~StrategyFactory() {}
public:
    TaxStrategy* NewStrategy() {
	// 后面讲解工厂模式的时候再添加,这里是策略模式的重点,怎么在二进制级别复用,如不停机扩展
    }
};

// 真正的复用指的是二进制意义的复用,而不是源代码级别的复用
int main()
{
    StrategyFactory* strategyFactory;
    SalesOrder2 sales_order2(strategyFactory);        
    sales_order2.CalculateTax();

    return 0;
}

四、策略模式要点总结

  1. Strategy及子类为组件提供了一些列可重用的算法,从而使得类型在运行时方便根据需要在各算法之间切换;
  2. 策略模式提供了用条件判断语句以外的一种可扩展的选择,消除条件语句的耦合性,含有多个条件分支的代码通常都需要策略模式;
  3. 如果策略对象没有实例变量,那么各个上下文可共享一个策略对象,从而节省对象开销.

五、 思路总结

  1. 使用策略模式重构if语句的情形,在于if的情形始终存在变化的情形;
  2. 如果if分支的情况永远不变,则if分支即可; Case1
  3. 如果if分支不变,但在某些情形下某些分支很大概率不会被执行,这是可能造成性能负担,这是也可以使用策略模式. Case2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值