23种设计模式之策略模式

来源:互联网 发布:命令行启动mysql 编辑:程序博客网 时间:2024/06/16 12:42

策略模式的定义:
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们还可以相互替换,策略模式让算法独立于使用它的客户端而独立变化。
策略模式的使用场景:

  • 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时
  • 需要安全地封装多种同一类型的操作时
  • 出现同一抽象类有多个子类,而又需要使用if-else或者 switch-case 来选择具体子类时

类图:
这里写图片描述

  • Context:用来操作策略的上下文环境
  • Stragety:策略的抽象
  • ConcreteStragegyA,ConcreteStragegyB,ConcreteStragegyC:具体的策略实现
    简单实现:
    通常如果一个问题有多个解决方案时,比较简单的方式就是利用if-else或者switch-case 方式来根据不同的场景选择不同的解决方案,OK,咱们以北京的公交车为例,参考《Android源码设计模式》,首先看下通常的编写方式
public class PriceCalculator {    //公交车类型    private static final int BUS = 1;    //地铁类型    private static final int SUBWAY = 2;    public static void main(String[] args) {        PriceCalculator calculator = new PriceCalculator();        System.out.println("坐16公里的公交车票价位:" + calculator.calculatePrice(16, BUS));    }    /**     * 北京公交车,十公里之内一元钱,超过十公里之后每加一元钱可以乘5公里     *     * @param km     * @return     */    private int busPrice(int km) {        //超过十公里的距离        int extraTotal = km - 10;        //超过的距离对5公里倍数        int extraFactor = extraTotal / 5;        //超过的距离对5公里取余        int fraction = extraTotal % 5;        //价格计算        int price = 1 + extraFactor * 1;        return fraction > 0 ? ++price : price;    }    /**     * 6公里(含)内3元,6~12公里(含)4元,12~22公里(含)5元,22~32公里(含)6元     *     * @param km     * @return     */    private int subwayPrice(int km) {        if (km <= 6) {            return 3;        } else if (km < 12) {            return 4;        } else if (km < 22) {            return 5;        } else if (km < 32) {            return 6;        }        return 7;    }    private int calculatePrice(int km, int type) {        if (type == BUS) {            return busPrice(km);        } else if (type == SUBWAY) {            return subwayPrice(km);        }        return 0;    }}

如果想增加一个选择,只能在else-if中添加

    private int calculatePrice(int km, int type) {        if (type == BUS) {            return busPrice(km);        } else if (type == SUBWAY) {            return subwayPrice(km);        }else if(type == TAXT) {            return taxiPrice(km);        }        return 0;    }

很明显,PriceCalculator 类不是单一职责,1.计算公交车和地铁乘坐价格的职责。2.还有就是通过if-else的形式来判断使用哪种计算形式。当增加一种出行方式时,就需要增加一个方法。如上代码所示。整体代码比较混乱,这就是我们的主人公—策略模式登场的时候了。我们可以把每一种情景独立成一个函数,然后外部调用方法即可,但是这也是另一种耦合形式,对于可变性较大的算法族来说还是不太适合。
策略模式代码重构如下:

//计算接口public interface CalculateStrategy {    /**     * 按距离来计算价格     * @param km     * @return     */    int calculatePrice(int km);}//公交车价格计算策略public class BusStrategy implements CalculateStrategy {    @Override    public int calculatePrice(int km) {        //超过十公里的距离        int extraTotal = km - 10;        //超过的距离对5公里倍数        int extraFactor = extraTotal / 5;        //超过的距离对5公里取余        int fraction = extraTotal % 5;        //价格计算        int price = 1 + extraFactor * 1;        return fraction > 0 ? ++price : price;    }}//地铁价格计算策略public class SubwayStrategy implements CalculateStrategy {    @Override    public int calculatePrice(int km) {        if (km <= 6) {            return 3;        } else if (km < 12) {            return 4;        } else if (km < 22) {            return 5;        } else if (km < 32) {            return 6;        }        return 7;    }}

我们再创建一个扮演角色Context角色的类

//公交出行价格计算器public class TranficCalculator {    public static void main(String[] args){        TranficCalculator calculator = new TranficCalculator();//        //设置策略模式        calculator.setStrategy(new BusStrategy());        //计算价格        System.out.println("公交车乘16公里的价格:"+calculator.calculatePrice(16));        //设置策略模式        calculator.setStrategy(new TaxiStrategy());        //计算价格        System.out.println("出租车乘16公里的价格:"+calculator.calculatePrice(16));    }    CalculateStrategy mStrategy;    public void setStrategy(CalculateStrategy mStrategy) {        this.mStrategy = mStrategy;    }    public int calculatePrice(int km){        return mStrategy.calculatePrice(km);    }}

这样代码就重构完成了,代码逻辑非常清晰,而且耦合性降低了,可扩展性变强了,现在如果增加一个出租车的方式,

//出租车计算策略public class TaxiStrategy implements CalculateStrategy {    @Override    public int calculatePrice(int km) {        return 2 * km;    }}

总结:
策略模式主要是用来分离算法,在相同的行为抽象下有不同的具体实现策略。这个模式很好地展示了开闭原则,也就是定义抽象,注入不同的实现,从而达到很好的可扩展性。
优点:

  • 结构清晰明了,使用简单直观
  • 耦合度相对而言较低,扩展方便
  • 操作封装也更为彻底,数据更安全

    缺点:

  • 随着策略模式的增加,子类也会变得繁多
  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类
  • Strategy和Context之间的通信开销

策略模式就到这里,大家对策略模式是不是又有了新的看法呢?
该文章参考《android源码设计模式解析与实战》这本书。

原创粉丝点击