策略模式

2019/08/28 设计模式 共 1803 字,约 6 分钟

策略模式

《Head First 设计模式》的第一章通过鸭子介绍的设计模式令人影响深刻,不看目录我还真没认出这就是策略模式…
今天要学习的是策略模式…

定义

Define a family of algorithms, encapsulate each one, and make them interchangeable.
译文:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。
百度百科:对象有某个行为,但是在不同的场景中,该行为有不同的实现算法

类图

图片来自百度百科

策略模式类图

角色结构

Strategy抽象策略角色:策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性。

  • 上下文角色Context使用此策略接口来调用具体的策略所实现的算法 ConcreteStrategy具体策略角色:实现抽象策略中的操作,该类含有具体的算法。
  • 具体的策略实现,即具体的算法实现 Context封装角色:它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
  • 上下文角色通常会持有一个抽象策略角色,利用多态来使用不同的策略(使用不同的具体策略角色实现的算法)

实例

背景:周末准备和同事去北高峰爬山,每个人从家里出发使用不同的交通工具到北高峰。
将人抽象成对象,每个人都会持有一个实现交通工具接口TrafficTools的对象tool,交通工具接口拥有一个出行的方法go(),是该交通工具上路的方法,而每个人通过持有的具体交通工具类调用该交通工具的出行方法,从而实现到达北高峰的目标。

  1. 首先创建一个策略接口TrafficTools,接口中有一个出行方法待实现.
public interface TrafficTools {

    /**
     * 交通工具出行方法
     */
    void go();
}
  1. 然后创建两个交通工具类,即具体策略实现角色,实现TrafficTools接口。
public class MotorBike implements TrafficTools {
    @Override
    public void go() {
        System.out.println("骑上我心爱的小摩托,它永远不会堵车");
    }
}

public class Car implements TrafficTools {
    @Override
    public void go() {
        System.out.println("小汽车嘟嘟嘟嘟嘟");
    }
}
  1. 最后创建策略上下文类,通过构造方法传入MotorBike类策略,Person的travel方法只负责调用策略实现类的go方法
public class Person {

    /**
     * 持有策略实现对象
     */
    private TrafficTools tool;

    public Person(TrafficTools tool) {
        this.tool = tool;
    }

    /**
     * 旅行方法
     */
    public void travel() {
        tool.go();
    }
}
  1. 创建测试类
public class Test {
    
    public static void main(String[] args) {
        // 通过构造方法传入MotorBike类策略,Person的travel方法只负责调用策略实现类的go方法
        Person me = new Person(new MotorBike());
        me.travel();
    }
}
  • 测试结果为
骑上我心爱的小摩托,它永远不会堵车

策略模式的优缺点

优点

  1. 算法(策略)可以自由切换:只需要在创建Person对象时传入不同的TrafficTools对象即可
  2. 避免使用多重判断条件
  3. 扩展性良好:只需要新建一个实现TrafficTools接口的策略类
public class Walk implements TrafficTools {
    @Override
    public void go() {
        System.out.println("自己走路");
    }
}

缺点

  1. 策略数量多,不可复用
  2. 所有的策略类都需要对外暴露。

    上层模块必须知道有哪些策略,然后才能决定使用哪个策略,这于迪米特法则是相违背的。
    迪米特法则:一个对象应该对其他对象有最少的了解

使用场景

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

源代码

GitHub地址

版权声明:本文为Planeswalker23所创,转载请带上原文链接,感谢。

文档信息

Search

    Table of Contents