What

策略模式,英文全称是 Strategy Design Pattern。在 GoF 的《设计模式》一书中,它是这样定义的:

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. 定义一组算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。

即:定义一组策略类,每个策略类实现相同的接口,让他们可以在运行时(创建、使用)相互替换,解耦策略的定义、创建、使用 这三部分。

  • 作用

策略模式主要的作用还是解耦策略的定义、创建和使用,控制代码的复杂度,让每个部分都不至于过于复杂、代码量过多。除此之外,对于复杂代码来说,策略模式还能让其满足开闭原则,添加新策略的时候,最小化、集中化代码改动,减少引入 bug 的风险。

How

经典的策略模式实现

  1. /**
  2. * 经典实现方式
  3. *
  4. * @author yiy
  5. * @date 12/30/2021
  6. */
  7. public class ClassicWay {
  8. public static void main(String[] args) {
  9. //运行时动态获取type(在程序运行期间,根据配置、用户输入、计算结果等这些不确定因素,动态决定使用哪种策略)
  10. String type = "A";
  11. IStrategy strategy = StrategyFactory.getStrategy(type);
  12. strategy.algorithmInterface();
  13. }
  14. }
  15. /**
  16. * 策略接口
  17. */
  18. interface IStrategy {
  19. /**
  20. * 策略函数
  21. */
  22. void algorithmInterface();
  23. }
  24. /**
  25. * 策略类A
  26. */
  27. class StrategyImplA implements IStrategy {
  28. @Override
  29. public void algorithmInterface() {
  30. //具体的算法...
  31. }
  32. }
  33. /**
  34. * 策略类B
  35. */
  36. class StrategyImplB implements IStrategy {
  37. @Override
  38. public void algorithmInterface() {
  39. //具体的算法...
  40. }
  41. }
  42. /**
  43. * 策略工厂
  44. * 策略类无状态,可复用(也可每次都new新的策略类,使其不可复用,相互隔离)
  45. */
  46. class StrategyFactory {
  47. /**
  48. * 策略缓存
  49. * 注意:更优雅的方式,可以把key用枚举来替换,使其更加符合内聚性
  50. */
  51. private static final Map<String, IStrategy> strategies = new HashMap<>();
  52. static {
  53. strategies.put("A", new StrategyImplA());
  54. strategies.put("B", new StrategyImplB());
  55. }
  56. public static IStrategy getStrategy(String type) {
  57. if (type == null || type.isEmpty()) {
  58. throw new IllegalArgumentException("type should not be empty.");
  59. }
  60. return strategies.get(type);
  61. }
  62. }

Why

vs 其他模式

应用案例

通过策略模式避免分支判断

根据不同类型的订单来实现不同的打折方式。

  • 非策略模式实现

    1. public class OrderService {
    2. public double discount(Order order) {
    3. double discount = 0.0;
    4. OrderType type = order.getType();
    5. if (type.equals(OrderType.NORMAL)) { // 普通订单
    6. //...省略折扣计算算法代码
    7. } else if (type.equals(OrderType.GROUPON)) { // 团购订单
    8. //...省略折扣计算算法代码
    9. } else if (type.equals(OrderType.PROMOTION)) { // 促销订单
    10. //...省略折扣计算算法代码
    11. }
    12. return discount;
    13. }
    14. }
  • 策略模式实现

    • 无状态(不包含成员变量,只是纯粹的算法实现),可复用 ```java // 策略的定义 public interface DiscountStrategy { double calDiscount(Order order); } // 省略实现类NormalDiscountStrategy、GrouponDiscountStrategy、PromotionDiscountStrategy类代码…

// 策略的创建 public class DiscountStrategyFactory { private static final Map strategies = new HashMap<>();

static { strategies.put(OrderType.NORMAL, new NormalDiscountStrategy()); strategies.put(OrderType.GROUPON, new GrouponDiscountStrategy()); strategies.put(OrderType.PROMOTION, new PromotionDiscountStrategy()); }

public static DiscountStrategy getDiscountStrategy(OrderType type) { return strategies.get(type); } }

// 策略的使用 public class OrderService { public double discount(Order order) { OrderType type = order.getType(); DiscountStrategy discountStrategy = DiscountStrategyFactory.getDiscountStrategy(type); return discountStrategy.calDiscount(order); } }


   - 有状态,不可复用
```java
public class DiscountStrategyFactory {
  public static DiscountStrategy getDiscountStrategy(OrderType type) {
    if (type == null) {
      throw new IllegalArgumentException("Type should not be null.");
    }
    if (type.equals(OrderType.NORMAL)) {
      return new NormalDiscountStrategy();
    } else if (type.equals(OrderType.GROUPON)) {
      return new GrouponDiscountStrategy();
    } else if (type.equals(OrderType.PROMOTION)) {
      return new PromotionDiscountStrategy();
    }
    return null;
  }
}

这种实现方式相当于把原来的 if-else 分支逻辑,从 OrderService 类中转移到了工厂类中,并没有真正将它移除。

  • 注意:

本质上是借助“查表法”,根据 type 查表(代码中的 strategies 就是表)替代根据 type 分支判断,如需完全避免分支判断可以通过反射来动态创建对象实现。