简介
策略模式(Strategy Pattern)属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
实例
策略模式及到三个角色:
- 抽象策略角色(Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口;
- 具体策略角色(ConcreteStrategy):包装了相关的算法或行为;
- 上下文角色(Context):对策略进行二次封装,目的是避免高层模块对策略的直接调用。
在电商系统中,通常会集成多种支付方式。下面以一个支付调用例子演示下策略模式。
抽象角色:
public interface IPayStrategy {
/**
* 调用支付
*/
void doPay();
}
具体策略模式:
// 支付宝支付
public class AliPayStrategy implements IPayStrategy {
@Override
public void doPay() {
System.out.println("调用支付宝支付~");
}
}
// 微信支付
public class WxPayStrategy implements IPayStrategy {
@Override
public void doPay() {
System.out.println("调用微信支付~");
}
}
上下文角色:
public class PayContext {
private IPayStrategy payStrategy;
public PayContext(IPayStrategy payStrategy) {
this.payStrategy = payStrategy;
}
/**
* 策略方法
*/
public void doPay() {
payStrategy.doPay();
}
}
客户端:
public class Client {
@Test
public void testPay() {
PayContext context;
//调用支付宝支付
context = new PayContext(new AliPayStrategy());
context.doPay();
// 调用微信支付
context = new PayContext(new WxPayStrategy());
context.doPay();
}
}
结果:
调用支付宝支付~
调用微信支付~
类图

优点
- 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复;
- 使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。
缺点
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况;
- 由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。
适用场景
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为;
- 一个系统需要动态地在几种算法中选择一种;
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
与 SPI 的区别
SPI 机制其实与 策略模式 类似。SPI 机制是 Java 中使用的一种技术实现,全称是 Service Provider Interface,即服务提供接口,一般用在开源框架研发领域。
策略模式 与 SPI 机制有下面几点异同:
- 从设计思想来看。策略模式和
SPI机制其思想是类似的,都是通过一定的设计隔离变化的部分,从而让原有部分更加稳定; - 从隔离级别来看。策略模式的隔离是类级别的隔离,而
SPI机制是项目级别的隔离; - 从应用领域来看。策略模式更多用在业务代码书写,
SPI机制更多用于框架的设计。
总结
策略模式 是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换。
策略模式 是一种简单常用的模式,我们在进行开发的时候,会经常有意无意地使用它,一般来说,策略模式 不会单独使用,跟 模版方法模式、工厂模式 等混合使用的情况比较多。