10.5.4 行为型设计模式-01
行为型模式关注对象之间的职责分配、通信和访问方式。创建型解决“对象怎么来”,结构型解决“对象怎么组”,行为型解决“对象怎么协作、怎么变化”。
行为型共有 11 种,数量最多,也是最容易混淆的一组。
行为型模式总览
| 中文名 | 英文名 | 一句话意图 | 题干关键词 |
|---|---|---|---|
| 职责链 | Chain of Responsibility | 让多个对象都有机会处理请求,请求沿链传递 | 层层审批、向上提交、直到有人处理 |
| 命令 | Command | 将请求封装成对象 | 请求对象、排队、日志、撤销 |
| 解释器 | Interpreter | 定义语言文法,并解释句子 | 文法、终结符、非终结符、解释 |
| 迭代器 | Iterator | 顺序访问聚合对象元素,不暴露内部表示 | 遍历、next、聚合对象 |
| 中介者 | Mediator | 用中介对象封装一组对象交互 | 多对象交互、降低耦合、都找中介 |
| 备忘录 | Memento | 在不破坏封装前提下保存对象状态 | 备份、恢复、快照 |
| 观察者 | Observer | 对象状态变化时通知所有依赖者 | 一对多联动、订阅、自动通知 |
| 状态 | State | 对象内部状态改变时改变行为 | 状态封装成类、不同状态不同行为 |
| 策略 | Strategy | 封装一组算法,使它们可互换 | 算法族、方案切换、折扣策略 |
| 模板方法 | Template Method | 父类定义算法骨架,子类实现可变步骤 | 算法骨架、模板填空、步骤延迟 |
| 访问者 | Visitor | 在不改变元素类的前提下增加操作 | visit、accept、数据与操作分离 |
职责链:请求沿链传递
职责链把多个处理者连成一条链。请求发送者只把请求交给链上的某个处理者,如果当前处理者不能处理,就继续向后传递,直到有人处理。
flowchart LR
Request["请假请求"] --> Leader["组长"]
Leader -- "权限不足" --> Manager["部门经理"]
Manager -- "权限不足" --> Director["总经理"]
Director --> Done["处理完成"]它的价值是降低发送者和多个接收者之间的耦合。发送者不需要知道谁最终处理,只需要把请求丢进链里。
考试关键词:层层审批、请求沿链传递、多个对象都有处理机会、不明确指定接收者。
命令:把请求封装成对象
命令模式把请求封装成对象。请求一旦成为对象,就可以被排队、记录、撤销、重做,也可以作为参数传递。
classDiagram
class Command {
+execute()
}
class ConcreteCommand
class Receiver {
+action()
}
class Invoker {
+setCommand(command)
+call()
}
Command <|.. ConcreteCommand
ConcreteCommand --> Receiver : action()
Invoker --> Command命令模式常见角色:
| 角色 | 作用 |
|---|---|
| Command | 声明执行请求的接口 |
| ConcreteCommand | 绑定接收者与具体动作 |
| Receiver | 真正知道如何执行请求 |
| Invoker | 要求命令对象执行请求 |
| Client | 创建命令并设置接收者 |
看到“排队、日志、撤销、在不同时刻安排请求”,优先想到命令。
解释器:按文法解释输入
解释器模式为某种语言定义文法表示,并定义解释器来解释该语言中的句子。课程把它类比成编译/虚拟机机制:输入语句,按规则转换,输出结果。
解释器类图里常出现:
- 抽象表达式
AbstractExpression - 终结符表达式
TerminalExpression - 非终结符表达式
NonterminalExpression - 上下文
Context
解释器在软考中考得相对少,但需要记住关键词:文法、解释、终结符、非终结符。
迭代器:顺序访问聚合对象
迭代器提供一种方法顺序访问聚合对象中的各个元素,而不暴露内部表示。
flowchart LR
Aggregate["聚合对象"] --> Iterator["迭代器"]
Iterator --> First["first()"]
Iterator --> Next["next()"]
Iterator --> Current["currentItem()"]许多现代语言已内置迭代器接口,所以考试通常不会要求自己实现完整迭代器,但会考“顺序访问聚合对象”“不暴露内部结构”“next 方法”等关键词。
中介者:把网状交互变成中心协调
中介者用一个中介对象封装一系列对象的交互。原本对象之间两两通信,关系会变成复杂网状;引入中介者后,每个对象只需要与中介者交互。
flowchart LR
A["对象A"] <--> M["中介者"]
B["对象B"] <--> M
C["对象C"] <--> M
D["对象D"] <--> M它和代理模式的区别很重要:
| 对比项 | 代理 | 中介者 |
|---|---|---|
| 解决问题 | 控制对某个对象的访问 | 协调多个对象之间的交互 |
| 关系形态 | 客户 -> 代理 -> 真实对象 | 多个对象都与中介者通信 |
| 是否改变交互结构 | 通常只是访问路径多一层 | 改变多对象交互方式 |
题干如果强调“多个对象交互复杂,通过中心对象协调”,选中介者。
备忘录:保存状态以便恢复
备忘录在不破坏封装的前提下,捕获对象内部状态,并在对象之外保存,以便以后恢复。
flowchart LR
Originator["原发器\n当前状态"] --> Memento["备忘录\n保存状态"]
Caretaker["管理者"] --> Memento
Memento --> Originator它的关键是“备份”和“恢复”。不是重新创建一个完整新对象,而是把需要恢复的状态保存起来。
观察者:一对多联动
观察者模式定义对象间一对多依赖。当一个对象状态变化时,所有依赖它的对象都会得到通知并自动更新。
classDiagram
class Subject {
+attach(observer)
+detach(observer)
+notify()
}
class ConcreteSubject
class Observer {
+update()
}
class ConcreteObserverA
class ConcreteObserverB
Subject <|-- ConcreteSubject
Observer <|.. ConcreteObserverA
Observer <|.. ConcreteObserverB
Subject o-- Observer课程强调“注册/订阅”:观察者先注册到主题中,主题状态变化时再通知所有观察者。看到“发布订阅”“自动通知”“一对多联动”,选观察者。
例题
自查要点
- 职责链为什么能降低请求发送者和处理者之间的耦合?
- 命令模式为什么能支持撤销和日志?
- 中介者和代理都加了一个对象,它们改变的关系有什么不同?
- 观察者模式中的注册、通知、更新分别对应什么?