关于 gof-strategy
为需要在多种算法间选择的开发者讲解策略设计模式,涵盖如何通过共同接口封装行为,以及何时不值得引入这层间接结构。
主要功能
- 01封装不同算法
- 02通过接口委托行为
- 03在运行时替换策略
- 04区分策略与相关模式
适用场景
- 01替换基于类型的算法分支
- 02无需大量子类即可改变行为
- 03有明确需求时增加第二种算法
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yonatankarp/ software-design-skills --skill gof-strategy安装后在 Claude Code 中输入/gof-strategy确认已加载。
详细介绍
一句话概述
将一系列相关算法分别封装在统一接口之后,让客户端在运行时组合所需的算法,而不是硬编码算法或根据类型标记进行分支判断。
何时使用此技能
- 类中有针对“类型”字段的
switch/if分支,用于在不同算法之间进行选择(排序顺序、定价规则、验证策略)。 - 为改变某一项行为而使用子类,导致类的数量呈组合式膨胀。
- 预计算法集会不断扩展。
- 两个类的大部分行为相同,但在某个单一维度上有所不同(例如,
MallardDuck和RubberDuck的区别仅在于它们如何叫、如何飞)。
何时不使用此技能
- 只有一种算法,也看不到近期会有第二种算法的迹象——增加间接层不符合 YAGNI 原则。
- 变化的行为涉及一系列步骤,但这些步骤的结构大多相同——这适用于
gof-template-method。 - 变化的是组合什么,而不是如何计算——这通常适用于
gof-decorator。
核心内容
策略模式将客户端要做什么与客户端如何做到解耦。客户端通过一个小型接口持有策略对象的引用;具体策略在构造时注入(也可以通过 setter 在运行时更改)。
组合优于继承:与其通过子类重写某个方法,不如注入一个负责该方法的小型对象。每种策略都可以独立测试,也可以在不修改宿主对象的情况下替换。
伪结构:
- 定义接口
Strategy { operate(input) }。 - 具体策略实现该接口:
StrategyA、StrategyB等。 - 上下文类持有一个
Strategy并委托调用:context.do(input) { strategy.operate(input) }。
判断启发
- 当你现在确实有 ≥2 种算法,或现在有一种算法且有充分、近期会实现第二种算法的理由时,使用此模式。
- 与其让每种算法都对应一个子类并导致类数量膨胀,不如优先采用策略模式。
- 如果策略无状态,可以使用
object实例(单例),而不必为每个上下文都分配实例。
反模式
- 仅仅“以防将来需要更多算法”就为单一算法引入策略模式——间接层的成本立刻显现,而收益可能永远不会出现。
- 策略对象携带过多状态——策略模式旨在封装行为;如果策略携带大量按调用变化的状态,应重新考虑职责边界。
- 按策略的实现方式命名(
FastSortStrategy、SlowSortStrategy),而不是按其在领域中的含义命名(PriorityFirstSort、ChronologicalSort)。
另请参阅
gof-state—— 结构相同,意图不同(策略模式改变计算内容;状态模式改变对象生命周期中的行为)。gof-template-method—— 当变化的是算法中的步骤,而不是整个算法时使用。gof-command—— 用于参数化操作,而不是算法。gof-kotlin-idioms—— 在 Kotlin 中,策略通常只是一个函数类型参数(T) -> R;无需接口。
参考资料
- Head First Design Patterns(第 2 版),第 1 章(“欢迎来到设计模式”)——经典的策略模式章节,以鸭子模拟器为例进行讲解。
评论
支持 Markdown