六、策略模式—旅行的交通工具 #和设计模式一起旅行#

兵无常势,水无常形,能因敌变化而取胜者,谓之神! ——《孙子兵法》

故事背景

旅行开始,我和设计模式mm要去的目的地很多,去往不同目的地可以选择的交通工具也是多样的,从北京到上海,我们可以选择自驾游、乘坐飞机、高铁,甚至是骑单车等等方式!每一种交通工具到达目的的时间也不同,假如从北京到上海,乘坐飞机两个小时,高铁五个小时,自驾游3天(3*24小时),每一种交通费也不一样!

假设如下,要完成1公里的路程,不同交通方式使用的时间不同!
1公里: 飞机 需要 1分钟
1公里: 高铁 需要 10分钟
1公里: 汽车 需要 30分钟
1公里: 自行车 需要 60分钟


public class TravelHappy{
    private int kilometers;//公里
    private String travelType;//交通工具类型

    public TravelHappy(){}

    public TravelHappy(int kilometers,String travelType){
        this.kilometers = kilometers;
        this.travelType = travelType;
    }

    //get set ..


    //计算花费的时间
    public int travelCostTime(){

        if("airplane".equals(this.travelType)){
            System.out.println("使用 "+ this.travelType + " 完成旅行...");
            return kilometers * 1;
        }else if("High_Speed_Rail".equals(this.travelType)){
            System.out.println("使用 "+ this.travelType + " 完成旅行...");
            return kilometers * 10 ;

        }else if("car".equals(this.travelType)){
            System.out.println("使用 "+ this.travelType + " 完成旅行...");
            return kilometers * 30 ;
        }

        return 0;
    }

}

public class Client{

    public static void main(String args[]){
        TravelHappy th = new TravelHappy();
        System.out.println("从北京到上海 1000公里");
        th.setKilometers(1000);
        th.setTravelType("airplane");
        int costTime;
        costTime = th.travelCostTime();
         System.out.println("-------costTime-------------" + costTime);
        System.out.println("--------------------");
        th.setTravelType("car");
        costTime = th.travelCostTime();
        System.out.println("-------costTime-------------" + costTime);


    }
}


从北京到上海 1000公里
使用 airplane 完成旅行...
-------costTime-------------1000 分钟
--------------------
使用 car 完成旅行...
-------costTime-------------30000 分钟

通过上面的例子,我们可以计算出使用不同的交通工具从一个地方到另一个地方所花费的时间。
每一种交通工具的使用其实就是一种策略,或者称为一种算法,但是上面的通过travelCostTime 来计算使用交通工具花费的时间并不是一个好的或者说完美的方案,存在一些问题。
- 如果要增加新的工具花费时间的计算,就要修改travelCostTime代码,违反了“开闭原则”,系统的灵活性和可扩展性不高。
- 如果增加的算法太多,就会造成太多的if..else… ,不利用维护。
- 也利于算法的重用,如果另外一个地方需要使用这个计算模式,需要拷贝粘贴来重用!

要解决上面的这些问题,设计模式MM推荐我看看策略模式。

故事主角-策略模式

策略模式: 定义了算法族,将算法分别封装起来,让他们之间可以互相替换,让算法的变化独立于具体使用算法的环境。

  • 算法封装起来,找到应用中可能需要变化的部分独立出来。
  • 可以互相替换,面向超类型编程,也就是面向抽象编程。
  • 算法的行为和具体使用的环境分别,方便算法可以重用。

策略模式类图

  • Context(环境类):环境类是使用算法的的角色,它在解决某个问题的时候可以采用多种策略。在环境类中维持一个抽象类的引用实力,用于定义采用的策略。
  • Strategy(抽象策略类):声明算法的抽象方法,是所有策略类的父类,可以是抽象类也可以是接口。环境类通过抽象策略类中声明的方法在运行时候调用具体策略类中的算法。
  • ContreteStrategy(具体策略类):实现抽象策略类中的方法,并定义自己的算法。

简要伪代码:

class abstract Strategy{

    public abstract int costTime();
}

class ContreteStrategyA extends Strategy{
    public int costTime(){

        //...具体的算法
    }
}

class Context{
    private Strategy strategy;

    //get set...
    public int travelCostTime(){

       return  strategy.costTime();
    }

}

class Cinent{
    Context context = new Context();  
    Strategy strategy;  
    strategy = new ConcreteStrategyA(); //可在运行时指定类型  
    context.setStrategy(strategy);  
    context.travelCostTime();  
}


武功修炼后

根据对策略模式的学习后,设计模式MM让我重新实现一下刚开始设计的TravelHappy,好吧!

public abstract class TravelStrategy {
    public abstract int costTime(int km);
}

public class AirPlaneTravelStrategy extends TravelStrategy {

    @Override
    public int costTime(int km) {
        return km * 1;
    }
}


public class CarTravelStrategy extends TravelStrategy {

    @Override
    public int costTime(int km) {
        return km * 1;
    }
}


public class CarTravelStrategy extends TravelStrategy {
    @Override
    public int costTime(int km) {
        return km * 30 ;
    }
}

public class TravelHappy {
    private TravelStrategy strategy;

    public TravelHappy(TravelStrategy strategy){
        this.strategy = strategy;
    }

    public int travelCostTime(int km){
        return strategy.costTime(km);
    }
}

public class Client {

    public static void main(String args[]){
        TravelStrategy strategy;
        TravelHappy th;
        //这里的策略可以使用配置文件进行读取
        strategy = new AirPlaneTravelStrategy();
        th = new TravelHappy(strategy);
        System.out.println("从北京到上海 1000公里");
        int costTime;
        costTime = th.travelCostTime(1000);
        System.out.println("-------costTime-------------" + costTime +" 分钟");

        System.out.println("--------------------");
        //这里的策略可以使用配置文件进行读取
        strategy = new CarTravelStrategy();
        th = new TravelHappy(strategy);
        costTime = th.travelCostTime(1000);
        System.out.println("-------costTime-------------" + costTime +" 分钟");
    }
}

从北京到上海 1000公里
使用飞机.......
-------costTime-------------1000 分钟
--------------------
使用汽车.......
-------costTime-------------30000 分钟

此时如果需要增加一个高铁的计算时间方法,原有代码均无须修改,只要增加一个新的高铁策略类作为抽象类的子类,实现在抽象类中方法,然后在客户端使用(客户端要使用配置文件方式进行读取),完全符合“开闭原则”。

故事结局

通过上面简单的对策略模式武功的学习,下面总结一下:
策略模式用于算法直接的自由切换和扩展,使用范围比较广泛。策略模式对应解决某一问题的算法族,允许用户从一个算法族中任意选择其中一个算法来解决某一个问题,同时可以方便的新增新的算法。

优点:
- 符合“开闭原则”,在不修改原有系统的基础上选择算法或者行为,并能灵活的扩展算法。
- 使用策略模式,避免了多重条件选择语句,方便系统维护。
- 将具体的策略提取并独立出来,可以在不同的环境类中复用,减少代码冗余,复用性更高。

缺点:
- 客户端必须要知道所有的策略类,自行决定使用哪一种策略。客户端在使用的时候就要知道每一种算法的区别,增加客户端使用难度。
- 如果策略比较多,会产生很多具体的策略类
- 客户端每次只可以使用一个策略类,使用多个策略类需要一个策略使用完在使用下一个。

使用场景:
- 客户端系统需要动态的在几种算法中选择一种。
- 如果算法有保密和安全性,不希望客户端知道,客户端只需要知道算法是做什么功能的即可。

实际生活场景:如超市商品的打折策略,一般游戏中选择难度级别(初级、、中级、高级),不同级别对应不同的实现策略。

到此策略模式告一段落,这篇内容对应策略模式就是初级级别。不管咋,设计模式MM告诉我不着急,一口气吃不成大胖子,一步也从北京跨不到上海,饭要一口一口吃,路要一步一步走。

Next 期待下一篇吧!! 在这么浪漫的旅途中,肯定会有很多人关注,下一篇介绍 观察者模式——关注我,分享旅途最浪漫的瞬间!

参考


如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到,谢谢!

如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
祝你今天开心愉快!


欢迎访问我的csdn博客,我们一同成长!

不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

博客首页 : http://blog.csdn.net/u010648555

猜你喜欢

转载自blog.csdn.net/u010648555/article/details/80503074