diff --git a/notes/设计模式 - 策略.md b/notes/设计模式 - 策略.md index 6c926792..8b617812 100644 --- a/notes/设计模式 - 策略.md +++ b/notes/设计模式 - 策略.md @@ -6,21 +6,13 @@ 策略模式可以让算法独立于使用它的客户端。 ### 类图 -- Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。 -- Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。 +- Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法; +- Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,即可以在运行时更换 Context 使用的算法。 下图按后文的鸭子示例画出:Duck 是 Context,QuackBehavior 是 Strategy,quack()、performQuack() 和 setQuackBehavior() 分别对应 behavior()、doSomething() 和 setStrategy()。

-### 与状态模式的比较 - -状态模式和策略模式的类图相似,都是通过组合一个接口对象来动态改变行为,区别在于这个对象是如何被切换的。 - -状态模式的 State 对象随运行过程中的状态转移而切换,转移由状态对象或 Context 的内部逻辑触发。例如订单处于“待支付”时调用 pay() 会完成支付,进入“已支付”后再调用 pay() 会被拒绝。 - -策略模式的 Strategy 对象由客户端创建并交给 Context,之后客户端通过 Context 使用它,需要时再替换为另一个策略。例如先为订单设置“标准快递”的运费计算策略,用户改选“加急”后替换为加急策略。 - ### 实现 设计一个鸭子,它可以动态地改变叫声。这里的算法族是鸭子的叫声行为。 @@ -221,12 +213,20 @@ public class FreightService { - 调用方要先选出策略,通常由工厂或 Map 负责。 注意事项: +- 工厂和 Spring 中的策略对象只有一个,被所有请求共享,应当是无状态的:计算过程中的数据放在参数和局部变量里,不要存到成员变量中,否则并发请求会互相覆盖,见[Bean 的作用域与线程安全](Spring.md#bean-的作用域与线程安全); - 策略接口只有一个方法、实现又很简单时,可以用 Lambda 代替实现类以减少类的数量,例如 `Map` 的值写成 `kg -> 25 + (kg - 1) * 6`([附录 A1](#a1-运费策略与-if-else-对拍)中验证了这种写法); - 模板方法通过继承固定算法的骨架,由子类覆写其中的步骤;策略通过组合替换整个算法; - 责任链中的请求依次经过多个处理者,策略则只选择一个算法执行; -- 代理模式与策略模式的类图相似,都是接口加组合,但代理的目的是控制对真实对象的访问,策略的目的是替换算法; - 用策略替代已有的 if-else 时,可以像[附录 A1](#a1-运费策略与-if-else-对拍)那样用同一组输入对比新旧实现的结果,确认一致后再切换。 +### 与状态模式的比较 + +[状态模式](设计模式%20-%20状态.md)和策略模式的类图相似,都是通过组合一个接口对象来动态改变行为,区别在于这个对象是如何被切换的。 + +状态模式的 State 对象随运行过程中的状态转移而切换,转移由状态对象或 Context 的内部逻辑触发。例如订单处于“待支付”时调用 pay() 会完成支付,进入“已支付”后再调用 pay() 会被拒绝。 + +策略模式的 Strategy 对象由客户端创建并交给 Context,之后客户端通过 Context 使用它,需要时再替换为另一个策略。例如先为订单设置“标准快递”的运费计算策略,用户改选“加急”后替换为加急策略。 + ### JDK 中的应用 - java.util.Comparator#compare() - java.util.concurrent.RejectedExecutionHandler#rejectedExecution():ThreadPoolExecutor 无法接收任务时调用它,AbortPolicy、CallerRunsPolicy、DiscardPolicy 和 DiscardOldestPolicy 是它的四种实现,通过构造方法或 setRejectedExecutionHandler() 设置。