1. 定义

策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换,让算法独立于使用它的客户而变化。

2. 作用

策略模式是对算法的封装,它把算法的责任和算法本身分离,委派给不同的对象管理。策略模式通常把算法封装到一系列的策略类里面,作为抽象策略类的子类。用一句话来说,就是「准备一组算法,并将每个算法封装起来,使得它们可以互换」。策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。

3. 角色

  • 上下文:对策略进行二次封装,目的是避免高层模块对策略的直接调用。
  • 抽象策略:通常情况下是一个接口,当各个实现类中存在着重复的逻辑时,则使用抽象类来封装这部分公共的代码,此时,策略模式看上去更像是模版方法模式。
  • 具体策略:具体策略角色通常由一组封装了算法的类来担任,这些类之间可以根据需要自由替换。

4. 实现

就拿出行方式来举个例子,我们去上班的方式有许多,可以开车、坐公交、骑车等。那么就可以把出行方式抽象出一个策略接口,各种具体的方式是策略实现,在出门时就可以自由选择啦。

类图
  1. 定义抽象策略,就是出行方式。
public interface IOutWay {
    /**
     * 外出方式
     */
    void goOut();
}
  1. 定义具体策略,可以是汽车、公交出行。
public class CarWay implements IOutWay {
    @Override
    public void goOut() {
        System.out.println("开汽车");
    }
}

public class BusWay implements IOutWay {
    @Override
    public void goOut() {
        System.out.println("做公交车");
    }
}
  1. 定义上下文,封装出行方式,调用其出行方法。
public class OutContext {
    private IOutWay outWay;

    public OutContext(IOutWay outWay) {
        this.outWay = outWay;
    }

    public void setOutWay(IOutWay outWay) {
        this.outWay = outWay;
    }

    public void go2Work() {
        outWay.goOut();
    }
}
  1. 测试。
public class StrategyTest {
    public static void main(String[] args) {
        OutContext outContext = new OutContext(new CarWay());
        outContext.go2Work();

        outContext.setOutWay(new BusWay());
        outContext.go2Work();
    }
}

5. 优缺点

1. 优点:
易于扩展,对「开闭原则」完美支持,在不修改原有系统的基础上,可以更换算法或者增加新的算法,提高了代码的复用性,是一种替换继承,避免多重条件转移语句的实现方式。

2. 缺点:
客户端必须知道所有的策略类,并理解其区别,同时在一定程度上增加了系统中类的个数,可能会存在很多策略类。

3. 使用场景:
在一个系统里面有许多类,它们之间的区别仅在于它们的行为,使用策略模式可以动态地让一个对象在许多行为中选择一种行为;一个系统需要动态地在几种算法中选择一种;避免使用难以维护的多重条件选择语句。

参考文章: