定义

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

结构和说明

示例代码

  1. public class StrategyDemo {
  2. /**
  3. * 策略,定义算法的接口
  4. */
  5. public static interface Strategy {
  6. /**
  7. * 某个算法接口,可以传入参数,也可以有返回值
  8. */
  9. void algorithmInterface();
  10. }
  11. /**
  12. * 实现的算法
  13. */
  14. public static class ConcreteStrategyA implements Strategy {
  15. @Override
  16. public void algorithmInterface() {
  17. // 具体的算法实现
  18. }
  19. }
  20. public static class ConcreteStrategyB implements Strategy {
  21. @Override
  22. public void algorithmInterface() {
  23. }
  24. }
  25. public static class ConcreteStrategyC implements Strategy {
  26. @Override
  27. public void algorithmInterface() {
  28. }
  29. }
  30. /**
  31. * 上下文对象,通常会持有一个具体的策略对象
  32. */
  33. public static class Context {
  34. /**
  35. * 持有一个具体的策略对象
  36. */
  37. private Strategy strategy;
  38. public Context(Strategy strategy) {
  39. this.strategy = strategy;
  40. }
  41. /**
  42. * 上下文对客户端提供的操作接口,可以有参数和返回值
  43. */
  44. public void contextInterface() {
  45. // 通常会转调具体的策略对象进行算法运算
  46. strategy.algorithmInterface();
  47. }
  48. }
  49. }

调用顺序

第一种

行为型模式-策略模式 - 图1

第二种

行为型模式-策略模式 - 图2

优缺点

优点

  • 定义一系列算法

策略模式的功能就是定义一系列算法,实现让这些算法可以相互替换。所以会为这一系列算法定义公共的接口,以约束一系列算法要实现的功能。如果这一系列算法具有公共功能,可以把策略接口实现为抽象类,把这些公共功能实现到父类中。

  • 避免多重条件语句

策略模式的一系列算法是平等的,是可以互相替换的,写在一起就是通过 if-else 结构来组织,如果此时具体的算法实现中又有条件语句,就构成了多重条件语句,使用策略模式能避免这样的多重条件语句。

  • 更好的扩展性

在策略模式中扩展新的策略实现非常容易,只要增加新的策略实现类,然后在使用策略的地方选择使用这个新的策略实现就可以了。

缺点

  • 客户端必须了解每种策略的不同

策略模式也有缺点,比如让客户端来选择具体使用哪一种策略,这就需要客户了解所有的策略,还要了解各种策略的功能和不同,这样才能做出正确的选择,而且这样也暴露了策略的具体实现。

  • 增加了对象数目

由于策略模式把每个具体的策略实现都封装成为类,如果备选的策略很多的话,那么对象的数目就会很客观。

  • 只适合扁平的算法结构

策略模式的一系列算法地位是平等的,是可以相互替换的,事实上构成了一个扁平的算法结构,也就是在一个策略接口下,有多个平等的策略算法,就相当于兄弟算法。而且在运行时刻只可以一个算法被使用,这就限制了算法使用的层级,使用的时候不能嵌套使用。
对于出现需要嵌套使用多个算法的情况,比如折上折、折后返券等业务的实现,需要组合或者嵌套多个算法的情况,可以考虑使用装饰模式,或是变形的职责链,或是AOP等方式来实现。

思考

本质

分离算法,选择实现。

何时选用

  • 出现有许多相关的类,仅仅是行为有差别的情况下,可以使用策略模式来使用多个行为中的一个来配置一个类的方法,实现算法动态切换。
  • 出现同一个算法,有很多不同实现的情况下,可以使用策略模式来把这些“不同的实现”实现成为一个算法的类层次。
  • 需要封装算法中,有与算法相关数据的情况下,可以使用策略模式来避免暴露这些跟算法相关的数据结构。
  • 出现抽象一个定义了很多行为的类,并且是通过多个 if-else 语句来选择这些行为的情况下,可以使用策略模式来代替这些条件语句。

相关模式

  • 策略模式和状态模式

这两个模式从模式结构上看是一样的,但是实现的功能却是不一样的。
状态模式是根据状态的变化来选择对应的行为,不同的状态对应不同的类,每个状态对应的类实现了该状态对应的功能,在实现功能的同时,还会维护状态数据的变化。这些实现状态对应功能的类之间是不能相互替换的。策略模式是根据需要或者是客户端的要求来选择相应的类,各个实现类是平等的,是可以相互替换的。另外策略模式可以让客户端来选择需要使用的策略算法;而状态模式一般是由上下文,或者是在状态实现类里面维护具体的状态数据,通常不由客户端来指定状态。

  • 策略模式和模版模版方法模式

这两个模式可以组合使用。
模版方法模式重在封装算法骨架;而策略模式重在分离并封装算法实现。

  • 策略模式和享元模式

这两个模式可组合使用。
策略模式分离并封装出一系列的策略算法对象,这些对象的功能通常比较单一,很多时候就是为了实现某个算法的功能而存在。因此,针对这一系列的,多个细粒度的对象,可以应用享元模式来节省资源,但是前提是这些算法对象要被频繁地使用,如果偶尔用一次,就没有必要做成享元了。