mcpField
G
gof-state

gof-state

github.com/yonatankarp开发143 次安装23 周前更新
代码仓库

关于 gof-state

讲解 GoF State 模式的技能,适用于状态会改变对象行为的场景。它介绍上下文、状态接口与具体状态,并帮助识别状态分支过多及非法转换等问题。

主要功能

  1. 01将状态行为封装在独立类中
  2. 02由上下文委托当前状态的操作
  3. 03描述状态转换与状态图
  4. 04比较 State 与 Strategy
  5. 05处理非法状态转换

适用场景

  1. 01状态枚举对应大型条件分支
  2. 02订单或连接具有明确生命周期状态
  3. 03状态转换受规则限制且集合固定

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yonatankarp/software-design-skills --skill gof-state

安装后在 Claude Code 中输入/gof-state确认已加载。

详细介绍

一句话概述

当对象的内部状态发生变化时,允许其改变行为——使对象看起来像是改变了自己的类。每种状态都封装在自己的类中;上下文将行为委托给它当前持有的状态。

何时使用此技能

  • 对象有多个定义明确的状态,且其行为会随所处状态而显著变化(糖果机、订单生命周期、网络连接、解析器)。
  • 当前实现中有一个很大的 switch 或针对状态枚举的 if-else,其中每个分支执行的操作都大不相同。
  • 状态集合有限且已知;状态之间的转换有限,并受规则约束。

何时不使用此技能

  • 只有两种状态,行为差异也很简单——单个布尔标志加一个小型 if 更简单。
  • 所谓的“状态”实际上是数据,而非行为——这种情况应使用值对象,而不是状态机。
  • 状态并非互斥(多个标志可以同时为真)——这不是状态机,而是功能标志矩阵。

核心内容

该模式包含三个部分:

  • 上下文——行为会发生变化的对象(糖果机)。它持有对当前 State 对象的引用,并公开委托给该对象的操作。
  • 状态接口——声明会随状态而变化的操作(insertQuarter()、ejectQuarter()、turnCrank()、dispense())。
  • 具体状态——实现 State 接口;每个具体状态代表一种特定状态,并具有自己的行为。状态转换通常由状态本身驱动——当前状态根据输入设置上下文的下一个状态。

此模式可以通过将状态实现为单例(无状态),或让每个状态持有对应上下文的状态来实现。优先选择更简单的形式。

State 与 Strategy。 结构完全相同:上下文将操作委托给可替换的行为对象。二者的意图不同:

  • Strategy:由客户端在构造时选择算法。
  • State:作为操作的结果,上下文在内部改变自身状态。

决策启发

  • 识别“按状态进行大型分支判断”的异味——这是采用 State 模式的典型理由。
  • 先定义状态图(有哪些状态、哪些转换合法)。状态类应与状态图一一对应。
  • 可以在上下文中集中处理状态转换(更简单,但上下文需要了解所有状态),也可以在状态类中处理(更分散,但每个状态都必须知道接下来会是什么状态)。

反模式

  • 状态爆炸——每个细微的行为变化都变成一个新的状态类。重新考虑这些变化是否真的是不同状态,还是仅仅是参数。
  • 状态不通过上下文的方法,而是直接修改上下文状态——这会让状态类与上下文的内部实现耦合。
  • 在“状态”实际上没有不同表现的用例中实现 State——这是在按模式给事物命名,而不是在使用模式。
  • 忘记处理非法转换——Dispensed 状态收到 insertQuarter() 调用时,应明确响应,而不是静默地不执行任何操作。

另请参阅

  • gof-strategy——结构相同,但意图不同(以及由谁来选择)。
  • gof-command——当某个操作触发状态转换时,该操作本身可以是 Command。
  • gof-kotlin-idioms——Kotlin 密封类与穷尽式 when 结合,可在编译时检查状态机,无需为每种状态分别创建子类。

参考资料

  • Head First Design Patterns(第 2 版),第 10 章(“事物的状态:State 模式”)——以糖果机为背景的经典阐述,其中包含 No-Quarter / Has-Quarter / Sold / Sold-Out 状态。

评论

支持 Markdown