行为模式
一、行为模式的第一性原理
1. 什么是“行为”?
在软件系统中,行为 = 在特定上下文中,对请求或事件做出的响应方式。
行为设计的核心矛盾并不在于“怎么写代码”,而在于以下问题:
- 行为由谁决定?
- 行为如何变化?
- 行为如何传播?
- 行为是否需要被记录、撤销、组合?
- 行为是否依赖稳定的数据结构或状态结构?
行为模式,本质上是对这些问题的不同回答。
二、行为模式的本质问题空间(总览模型)
从第一性原理出发,GOF 行为模式可以归入 5 类稳定问题空间:
2.1 行为由谁决定?(Decision Ownership)
- 对象自身决定:状态模式
- 外部注入决定:策略模式
核心矛盾: 行为切换的控制权是在对象内部,还是在对象外部?
2.2 行为如何传播?(Behavior Propagation)
- 线性传播:责任链
- 中心协调:中介者
- 广播传播:观察者
核心矛盾: 请求或事件是逐级传递、集中调度,还是去中心广播?
2.3 行为是否需要对象化?(Behavior as Object)
- 是:命令
- 否,结构固化:模板方法
核心矛盾: 行为是否需要被记录、排队、撤销、组合、持久化?
2.4 行为是否依赖稳定结构?(Structural Stability Assumption)
- 强依赖结构稳定:访问者、解释器
- 弱依赖或无依赖:其他大多数模式
核心矛盾: 是“数据结构稳定,操作常变”,还是“结构与行为一起变化”?
2.5 行为如何被遍历?(Traversal Control)
- 由客户控制:外部迭代器
- 由容器控制:内部迭代器
核心矛盾: 遍历控制权在使用者还是数据结构本身?
三、模式级重构(从“定义”到“设计哲学”)
以下不再重复教科书式定义,而统一采用:
- 本质问题
- 设计哲学
- 引入的代价
- 稳定前提
- 工程判断信号
四、行为切换类模式
4.1 状态模式(State)
本质问题:
行为随内部状态变化而变化,避免条件分支爆炸。
设计哲学:
- 将“状态 × 行为”的组合关系,拆解为独立状态对象
- 行为切换权在对象内部
引入的代价:
- 状态类数量膨胀
- 状态迁移关系复杂
稳定前提:
- 状态集合相对稳定
工程判断信号:
- 出现大量
if/else或switch(state) - 行为与状态强绑定
4.2 策略模式(Strategy)
本质问题:
在不修改上下文的前提下,替换不同算法或行为。
设计哲学:
- 行为是可插拔的
- 行为选择权在客户端或装配阶段
引入的代价:
- 客户端必须理解策略差异
- 参数传递可能膨胀
稳定前提:
- 策略可独立演化
工程判断信号:
- 多套算法,切换规则清晰
- 不希望上下文感知状态变化
五、行为传播类模式
5.1 责任链(Chain of Responsibility)
本质问题:
请求的处理者不确定,需要在多个处理者之间动态传递责任。
设计哲学:
- 解耦请求发送者与具体处理者
- 责任是“可转移的”
关键特性:
- 不保证请求一定被处理
引入的代价:
- 调试困难
- 链路过长导致性能与可观测性问题
工程判断信号:
- 多级校验 / 过滤 / 拦截
5.2 中介者(Mediator)
本质问题:
多对象交互形成网状依赖,导致系统失控。
设计哲学:
- 用中心协调者替代对象之间的多对多通信
引入的代价:
- 中介者可能演化为“上帝对象”
工程判断信号:
- 对象之间调用关系混乱
- 修改一个对象影响多个对象
5.3 观察者(Observer)
本质问题:
状态变化需要通知多个依赖方。
设计哲学:
- 广播而非点对点调用
- 目标与观察者解耦
引入的代价:
- 通知顺序不可控
- 可能引发级联更新
工程判断信号:
- 事件驱动
- UI / 领域事件
六、行为对象化与结构化模式
6.1 命令(Command)
本质问题:
将“请求”本身作为一等对象对待。
设计哲学:
- 行为对象化
- 支持撤销、排队、组合
引入的代价:
- 类数量增加
工程判断信号:
- 需要操作历史、事务、审计
6.2 模板方法(Template Method)
本质问题:
算法结构稳定,局部步骤易变。
设计哲学:
- 用继承固化流程骨架
引入的代价:
- 扩展依赖继承层级
工程判断信号:
- 流程固定、步骤可替换
七、结构稳定性假设类模式
7.1 访问者(Visitor)
本质问题:
在不修改数据结构的前提下,增加新行为。
设计哲学:
- 数据结构稳定,操作多变
引入的代价:
- 新增 Element 成本极高
工程判断信号:
- 编译器、AST、报表系统
7.2 解释器(Interpreter)
本质问题:
用对象结构表示语法规则并执行。
设计哲学:
- 文法即模型
工程判断信号:
- DSL、小型规则引擎
八、遍历控制类模式
8.1 迭代器(Iterator)
本质问题:
在不暴露内部结构的情况下遍历集合。
设计哲学:
- 遍历与结构解耦
九、模式对比速查矩阵
| 维度 | 状态 | 策略 | 命令 | 责任链 |
|---|---|---|---|---|
| 行为决定者 | 对象自身 | 客户端 | 调用者 | 链路 |
| 是否可撤销 | 否 | 否 | 是 | 否 |
| 行为对象化 | 否 | 否 | 是 | 否 |
| 状态关联性 | 强 | 无 | 无 | 弱 |
十、现代架构中的行为模式映射
- 观察者 → 事件总线 / MQ
- 命令 → CQRS / 消息
- 中介者 → Saga / Orchestrator
- 状态 → 显式状态机
- 责任链 → Pipeline / Filter Chain
十一、结语:行为模式的真正价值
行为模式不是为了“多用设计模式”, 而是为了用更低的认知成本,管理系统行为复杂性。
使用行为模式前先问:
- 我的行为复杂性来自哪里?
- 谁在决定行为?
- 行为是否需要被记录、传播、演化?