Head First设计模式之策略模式(Strategy)

        小白将从以下几点对策略模式进行解析

  • 策略模式引入的设计技巧

  • 策略模式的定义及类图

  • 策略模式的优缺点

  • 策略模式的应用场景

  • 策略模式实战

  • 总结

 

零、策略模式引入的技巧

  先过一遍,放入脑海中,等看完后面所有的内容,可以结合上下文进行消化

  我们要做的不是看过、读过、理解过、消化过,而是需要将其平常化,使用模式就像使用变量一样简单。

  1. 封装变化(把会变化的部分取出并“封装”起来,好让其他部分不会受到影响,这样一来,代码变化引起的不经意后果变少,系统变得更有弹性)

  2. 针对接口编程,而不是针对实现编程(可以把具体的实现延迟到”运行时“,执行时会根据实际状况执行到真正的行为,不会在编译时直接绑死,充分利用多态使系统更有弹性)

  3. 多用组合,少用继承("有一个”可能比“是一个”更好,可以在“运行时”动态的改变具体的实现,这样使系统有很大的弹性)

一、策略模式的定义及类图

  定义:定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。(PS:不要一带而过,停下来思考一下这句话的含义,多思考标注颜色的词语)

  类图:类图中一共有三个角色(至少三个角色),抽象策略角色具体策略角色环境角色

  1. 抽象策略角色:策略类,通常由一个接口或者抽象类实现
  2. 具体策略角色:包装了相关的算法和行为(算法和行为 对于策略模式来说是一样的,只是基于的角度不同,所以叫法不同而已
  3. 环境角色:持有一个策略类的引用,最终提供给客户端调用

   以下是UML类图:

      

 

 

 二、策略模式的优缺点

    优点:

    1. 可以动态的改变对象的行为而不需要客户端做任何的改动(从定义中就能看出来)
    2. 使用策略可以避免多重转移语句(比如 if else)。多重转移语句不便于维护,并且这种写法将采取哪一种算法的逻辑和算法的逻辑混合在一起,高耦合了
    3. 恰当的使用继承可以将公共的代码转移到父类(抽象策略角色)中,避免重复代码《此有点并非策略模式独有的优点,凡是采用继承的都可以拥有该优点

     缺点:

    1. 对于客户端来说,它必须知道所有的策略类,这样便可以根据不同的场景使用不同的策略类来完成当前的task。
    2. 策略模式的出现会引入许多的策略类,因此一般使用策略模式时需要考虑类泛滥的问题,一般4.5个具体策略类比较合适

  三、策略模式的应用场景

    1. 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为
    2. 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现
    3. 对客户隐藏具体策略(算法)的实现细节,彼此完全独立

            实际应用场景如下:(好好结合以下实际场景和上述语句进行融合)

    1. 比如买东西支付,你可以使用微信支付、支付宝支付、银行卡支持、pos机支付、零钱支持,具体使用哪种支付方式您肯定需要根据当时的场景来进行选择。
    2. 比如出行,您可以选择自行车出行、开车出行、走路出行、坐地铁出行。
    3. 再不如聊天,您可以选择微信聊天、QQ聊天、电话聊天。 等等

      根据当时环境选择哪一种方式进行后续动作便是策略。

 四、策略模式实战

  以下代码不会太复杂,只是作为示例,我这边已支付来进行实战

  抽象策略角色设计如下

/**
 * @Author: wander
 * @Descripttion: 抽象策略角色
 * @Date: 2018年07月15日22时40分
 */
public interface Pay {

    void pay(Integer money);

}

  三个具体策略角色设计如下

  

/**
 * @Author: wander
 * @Descripttion: 支付宝支付
 * @Date: 2018年07月15日22时43分
 */
public class AliPay implements Pay {

    public void pay(Integer money) {
        System.out.println("支付宝支付了" + money + "元");
    }
}
/**
 * @Author: wander
 * @Descripttion: 微信支付
 * @Date: 2018年07月15日22时41分
 */
public class WeChatPay implements Pay{

    public void pay(Integer money) {
        System.out.println("微信支付了" + money + "元");
    }

}
/**
 * @Author: wander
 * @Descripttion:
 * @Date: 2018年07月15日22时44分
 */
public class BankCardPay implements Pay {

    public void pay(Integer money) {
        System.out.println("银行卡支付了" + money + "元");
    }
}

  环境角色

/**
 * @Author: wander
 * @Descripttion: 环境角色
 * @Date: 2018年07月15日22时49分
 */
public class Person {

    private Pay pay;

    private Integer money;

    public Person(Integer money) {
        this.money = money;
    }

    public void pay(Pay pay) {
        pay.pay(money);
    }

}

 运行类

/**
 * @Author: wander
 * @Descripttion: 运行环境类
 * @Date: 2018年07月15日22时52分
 */
public class Strategy {

    public final static Integer TEN = 10;

    public static void main(String[] args) {
        WeChatPay weChatPay = new WeChatPay();
        AliPay aliPay = new AliPay();

        Person person = new Person(TEN);
        person.pay(weChatPay);
        person.pay(aliPay);

    }

}

运行结果如下:

微信支付了10元
支付宝支付了10元

五、总结

  当你需要根据不同的情况选择不同的方式处理问题,并且对使用者隐藏处理问题的过程,同时使用者可以随时更换处理方式而不需要做任何的改动

便可以使用策略模式

posted @ 2018-07-15 20:39  无期(瑶瑶)  阅读(313)  评论(0编辑  收藏  举报