首页/开发/代码质量与评审速查/行为型模式选型速查(Strategy/State/Observer/Command 等)
设计原则与模式62 条

行为型模式选型速查(Strategy/State/Observer/Command 等)

行为型模式都在分配职责与交互:算法替换用 Strategy、状态迁移用 State、一对多通知用 Observer、请求对象化用 Command、算法骨架用 Template Method;先描述问题再选模式。

行为型模式解决什么

行为型模式关注对象之间如何分工与通信,回答「谁负责处理、什么时候切换、结果通知给谁」,不涉及对象的创建与组装。它把这些判断从散落的条件分支里提出来,变成可命名的结构,让变化点集中在一处。GoF 归纳的行为型模式有十一种,评审中出现频率最高的是 Strategy、State、Observer、Command、Template Method 五种,其余多是它们的组合或变体。

选型判断顺序

第一步先用业务语言说出变化点在哪里
第二步确认只有一个变化轴再套模式
第三步看语言原生手段是否已经够用
兜底模式名是命名工具,不是设计目标

行为型模式对照

模式一句话典型信号
Strategy可替换的算法族同一计算有多种口径,按场景切换
State行为随状态改变对象里有状态字段与迁移分支
Observer变更广播给订阅者同一事件有多处需要感知
Command把请求对象化需要排队、撤销或审计操作
Template Method骨架固定步骤可变多个流程只有个别步骤不同
Chain of Responsibility沿链依次尝试处理校验、审批等管线式处理
Mediator集中协调多方交互网状依赖需要收敛到一个协调者

典型使用场景

  • 计费口径按客户类型切换:把每种算法独立成类,替代散落的 if 分支
  • 订单状态机:待支付、已支付、已发货各阶段行为不同,用 State 收拢迁移规则
  • 配置变更要通知缓存、日志、监控多处:用 Observer 替代逐处硬编码调用
  • 运维操作需要审批与撤回:封装成 Command 后自然获得排队与撤销能力
  • 数据流程只有清洗步骤因数据源而异:用 Template Method 固定流程骨架
  • 导入管线依次做格式、权限、重复校验:用责任链把校验步骤串起来

策略与状态的分界

策略与状态的分界
# 策略:由调用方决定用哪一个(外部选择)
price = PRICING[strategy].calc(order)

# 状态:由对象内部按当前状态决定下一步(内部迁移)
order.pay()   # 内部把状态从待支付推进到已支付
order.pay()   # 再次调用因状态不同而报错或忽略
Strategy 与 State 的结构几乎一样,差别在谁来切换:策略由外部选定并替换,状态由对象内部按事件迁移。判断时问一句「换算法是调用方的意图吗」,答案是是,则应归为策略。
Observer 在语言层面已有等价物:事件总线、回调注册、响应式流。用了语言设施就不必再手写注册与注销逻辑,但要明确订阅的生命周期与取消时机,否则会出现已销毁对象仍被通知。

落地检查清单

  • 变化点被隔离在一个接口后面,而不是散落在各个调用方
  • 新增一种算法或状态时只需加类,不必修改已有分支
  • 每个模式类都能用一句话说清自己的职责
  • 测试可以单独替换其中一个实现,而不必重建整个对象图

常见混淆对照

疑问分辨方式
策略还是状态切换的发起方在外部是策略,在对象内部是状态
观察者还是中介者单向广播用观察者,多方互相协调用中介者
命令还是策略封装要做的事用命令,封装怎么算用策略
责任链还是装饰器责任链到一个处理者就停,装饰器逐层叠加且都执行

易错点

  • 按模式名选方案:先有结论再找理由,会引入与问题不匹配的抽象层,改动量翻倍而问题依旧
  • 同一处叠用多个模式:不先回答谁是唯一变化点,接口数量膨胀,阅读者无法判断调用路径
  • 把简单分支包装成策略:只有两种取值且短期不扩展时,直接写条件分支更易读,模式类反而增加跳转
  • 忽略模式带来的间接层:一次调用要跨三层才到实现,调试与断点定位成本显著上升

数据来源与参考

  • 《设计模式》(GoF)· 行为型模式意图综述
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌