友情支持

如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

支付宝

微信

有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。

wx jikerizhi

公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。

23. 策略模式

23.1. 定义

根据 GoF 的著名著作 《设计模式》,策略模式的定义如下:

策略模式(Strategy)

它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

— Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides
《设计模式》

23.2. 类图

Diagram

面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。

策略模式定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

商场收银时如何促销,用打折还是返利,其实都是一些算法,用工厂来生成算法对象,这没有错,但算法本身只是一种策略,最重要的是这些算法是随时都可能互相替换的,这就是变化点,而封装变化点是我们面向对象的一种很重要的思维方式。

Strategy类,定义所有支持的算法的公共接口

ConcreteStrategy,封装了具体的算法或行为,继承于Strategy

Context,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用。

策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合[DPE]。

策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能[DP]。

策略模式的优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试[DPE]。

当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为。将这些行为封装在一个个独立的Strategy类中,可以在使用这些行为的类中消除条件语句[DP]。

策略模式封装了变化。

策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性[DPE] 注: 我觉得可以使用策略模式、责任链模式和动态表单实现一个灵活的促销系统。思考一下如何实现?

在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象[DPE]

任何需求的变更都是需要成本的。

高手和菜鸟的区别就是高手可以花同样的代价获得最大的收益或者说做同样的事花最小的代价。面对同样的需求,当然是改动越小越好。

代码 133. strategy/Client.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package com.diguage.didp.strategy;

/**
 * Client 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-16
 */
public class Client {
  public static void main(String[] args) {
    Context context = new Context(new ConcreteStrategyA());
    context.contextInterface();

    context.setStrategy(new ConcreteStrategyB());
    context.contextInterface();

    context.setStrategy(new ConcreteStrategyC());
    context.contextInterface();
  }
}
代码 134. strategy/ConcreteStrategyA.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package com.diguage.didp.strategy;

/**
 * 具体算法 A
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-16
 */
public class ConcreteStrategyA extends Strategy {
  public void algorithmInterface() {
    System.out.println("算法A实现");
  }
}
代码 135. strategy/ConcreteStrategyB.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package com.diguage.didp.strategy;

/**
 * 具体算法 B
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-16
 */
public class ConcreteStrategyB extends Strategy {
  public void algorithmInterface() {
    System.out.println("算法B实现");
  }
}
代码 136. strategy/ConcreteStrategyC.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package com.diguage.didp.strategy;

/**
 * 具体算法 C
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-16
 */
public class ConcreteStrategyC extends Strategy {
  public void algorithmInterface() {
    System.out.println("算法C实现");
  }
}
代码 137. strategy/Context.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.diguage.didp.strategy;

/**
 * Context 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-16
 */
public class Context {
  private Strategy strategy;

  public Context(Strategy strategy) {
    this.strategy = strategy;
  }

  public void contextInterface() {
    strategy.algorithmInterface();
  }

  public void setStrategy(Strategy strategy) {
    this.strategy = strategy;
  }
}
代码 138. strategy/Strategy.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package com.diguage.didp.strategy;

/**
 * Strategy 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-23 09:09:50
 */
public abstract class Strategy {
  public abstract void algorithmInterface();
}

23.3. 常见示例

  1. java.util.Comparator

  2. jakarta.servlet.http.HttpServlet

  3. jakarta.servlet.Filter.doFilter(ServletRequest request, ServletResponse response, FilterChain chain)