行为型模式解决什么
行为型模式关注对象之间如何分工与通信,回答「谁负责处理、什么时候切换、结果通知给谁」,不涉及对象的创建与组装。它把这些判断从散落的条件分支里提出来,变成可命名的结构,让变化点集中在一处。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 在语言层面已有等价物:事件总线、回调注册、响应式流。用了语言设施就不必再手写注册与注销逻辑,但要明确订阅的生命周期与取消时机,否则会出现已销毁对象仍被通知。
落地检查清单
- 变化点被隔离在一个接口后面,而不是散落在各个调用方
- 新增一种算法或状态时只需加类,不必修改已有分支
- 每个模式类都能用一句话说清自己的职责
- 测试可以单独替换其中一个实现,而不必重建整个对象图
常见混淆对照
| 疑问 | 分辨方式 |
|---|---|
| 策略还是状态 | 切换的发起方在外部是策略,在对象内部是状态 |
| 观察者还是中介者 | 单向广播用观察者,多方互相协调用中介者 |
| 命令还是策略 | 封装要做的事用命令,封装怎么算用策略 |
| 责任链还是装饰器 | 责任链到一个处理者就停,装饰器逐层叠加且都执行 |