开始

  • 商场的收银软件:业务员根据购买商品的单价和数量向客户收费

  • 基础的实现:就是遍历后累加

变更

  • 超时推出了全场打八折活动

    • 前端添加一个变量标识活动,计算结果根据活动标识做响应的打折
  • 人气多了,改变了活动规则,满300打8折

  • 简单工厂模式虽然解决对象的创建问题,但是工厂类中需要根据收费方式创建对象,如果活动变化大,每次维护和扩展都需要改工厂类

策略模式

  • 策略模式(Strategy)属于对象行为型设计模式,主要是定义一系列的算法,把这些算法一个个封装成拥有共同接口的单独的类,并且使它们之间可以互换。

  • 策略模式使这些算法在客户端调用它们的时候能够互不影响地变化。这里的算法不要狭义的理解为数据结构中算法,可以理解为不同的业务处理方法。

  • 这种做法会带来什么样的好处呢? 它将算法的使用和算法本身分离,即将变化的具体算法封装了起来,降低了代码的耦合度,系统业务策略的更变仅需少量修改。 算法被提取出来,这样可以使算法得到重用,这种情况还可以考虑使用享元模式来共享算法对象,来减少系统开销(但要注意使用享元模式的建议条件)。

结构

  • 策略模式由三个角色组成:

    • 算法使用环境(Context)角色:算法被引用到这里和一些其它的与环境有关的操作一起 来完成任务。
    • 抽象策略(Strategy)角色:规定了所有具体策略角色所需的接口。在 java 它通常由接口 或者抽象类来实现。
    • 具体策略(Concrete Strategy)角色:实现了抽象策略角色定义的接口。

实现

  • CashSuper就是一个抽象策略,他的实现类就是具体策略

  • 在原有基础上添加Content类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class CashContext{
    private CashSuper cs;
    // 构造方法传入具体的收费策略
    public CashContext(CashSuper csuper){
    this.cs = csuper;
    }

    pulic double getResult(double money){
    // 根据收费策略运算
    return cs.acceptCash(money);
    }
    }

问题

  • 策略模式后,客户端创建CashContext后需要指定CashSuper,需要客户端去判断用哪一个算法

    1
    2
    3
    4
    5
    6
    CashContext cc = null;
    switch (item){
    case "打八折": cc = new CashRebate("0.8");
    // ....
    }
    double total = cc.getResult(1000);

结合工厂模式

  • 使用工厂模式与策略模式结合

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class CashContext{
    private CashSuper cs;
    // 构造方法传入具体的收费类型
    public CashContext(CashSuper csuper){
    switch (item){
    // 应用简单工厂: 将实例化策略放到context类中
    case "打八折": this.cs = new CashRebate("0.8");break;
    // ....
    }
    }

    pulic double getResult(double money){
    // 根据收费策略运算
    return cs.acceptCash(money);
    }
    }
  • 客户端使用

    1
    2
    3
    4
    5
    6
    // 简单工厂
    CashSuper cs = CashFactory.createCashAccept("打八折");
    cs.getResult(money);

    // 简单工厂+策略模式
    new CashContext("打八折").getResult(money);
  • 简单工程模式需要客户端认识二个类 CashSuper, CashFactory

  • 策略模式与简单工厂结合后,只需要认识CashContext 就可以,耦合度降低了,CashContext#getResult方法使得具体的收费方式也与客户端分离