行为模式
一、行为模式的第一性原理
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
十一、结语:行为模式的真正价值
行为模式不是为了“多用设计模式”,而是为了用更低的认知成本,管理系统行为复杂性。
使用行为模式前先问:
- 我的行为复杂性来自哪里?
- 谁在决定行为?
- 行为是否需要被记录、传播、演化?
关联内容(自动生成)
- [/软件工程/设计模式/设计模式.html](/软件工程/设计模式/设计模式.html) 介绍了设计模式的基本概念、关键属性和演化规律,是理解行为模式的基础
- [/软件工程/设计模式/结构型模式.html](/软件工程/设计模式/结构型模式.html) 与行为模式共同构成设计模式体系,结构型模式关注类和对象的组合,与行为模式的对象职责分配形成互补
- [/软件工程/设计模式/创建型模式.html](/软件工程/设计模式/创建型模式.html) 与行为模式同属GOF设计模式体系,创建型模式关注对象创建,行为模式关注对象职责分配,两者共同构成完整的模式体系
- [/编程语言/JAVA/JakartaEE/Servlet.html](/编程语言/JAVA/JakartaEE/Servlet.html) Servlet规范体现了多个经典的设计模式,包括行为模式中的模板方法模式、观察者模式和责任链模式等
- [/编程语言/编程范式/函数式编程.html](/编程语言/编程范式/函数式编程.html) 函数式编程中的高阶函数、函数作为参数等概念与行为模式中的策略模式、模板方法模式等有对应关系
- [/软件工程/架构/系统设计/可观测性.html](/软件工程/架构/系统设计/可观测性.html) 系统可观测性中的事件监控、日志记录等机制与行为模式中的观察者模式、命令模式等有密切关系
- [/计算机网络/网络安全/安全架构.html](/计算机网络/网络安全/安全架构.html) 安全架构中应用了多种设计模式,包括策略模式用于动态配置访问策略,观察者模式用于监控安全事件
- [/数据技术/流处理.html](/数据技术/流处理.html) 流处理系统中的处理模式与行为模式中的责任链、观察者等模式在事件处理和传播方面有相似之处
- [/软件工程/微服务/服务治理/服务容错.html](/软件工程/微服务/服务治理/服务容错.html) 服务容错设计中包含多种设计模式,与行为模式中的策略、命令等模式在处理分布式系统行为方面有共通点