4-策略模式(Strategy)

1. 动机

  • 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂,而且有时候支持不使用的算法也是一个性能负担 (资源浪费)。
  • 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?

2. 模式定义

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

  • 用拓展的方式,应对未来的算法层面的需求变化

实例:

  • 跨国电商 - 税务计算

  • 业务变化 - 时间轴 - 增加其他国家的税务计算方式

//结构化软件设计 - 面向过程

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){	//业务更改
            //FR********
        }
        /*
        	业务更改 违反了开发封闭原则 OCP
        	- 对扩展开放, 对更改封闭
        	- 需求变更 => 增加代码 而不是修改代码
        	- 直接修改源代码, 会增加不必要的成本(重新编译 测试 部署)
        */
        
        //...
    }
}
  • 不要以静态地眼光去看待软件结构的设计, 而是拥有动态思维
  • 即, 时间轴的概念: 过去——现在——将来 [问题的暴露]
  • 业务代码 软件架构怎么变化?怎么应对变化?
//面向对象软件设计

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);//多态调用
        //...
    }
};
  • 复用性指的是 编译单位,二进制层面的复用,
    而不是源代码层面的复用(Ctrl + C/V)
  • 性能负担:CPU高级缓存 - 内存 - 硬盘(虚拟内存)

3. 结构

在这里插入图片描述

  • 稳定的部分
    • Context
    • Strategy
  • 变化的部分
    • ConcreteStrategyA
    • ConcreteStrategyB
    • ConcreteStrategyC

4. 要点总结

  • Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要各个算法之间进行切换

  • Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。

    switch-case 或着 if-else-if

    这是结构化软件设计时代,分而治之的思维

    不同的情况,不同的应对策略,

    但在时间轴上来看,不可能预测未来的情况,
    也就是列举所有的情况,来分而治之的进行解决

    一旦情况变化就需要修改源代码,违背开发封闭原则

    所以,看到 条件判断语句 思考是否可用 Strategy 模式替代

    当然,也不是所有的条件判断语句都用 Strategy 模式替代,

    条件判断语句绝对稳定、不会发生变化的情况下,则不需要替代。

    比如,确定的公认事实,一周有七天,可确定的情况

    “看到 if-else-if 闻到坏代码的味道”

  • 如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值