Skip to content
难度基础(★)
建议时长45分钟

10.5.4 行为型设计模式-01

行为型模式关注对象之间的职责分配、通信和访问方式。创建型解决“对象怎么来”,结构型解决“对象怎么组”,行为型解决“对象怎么协作、怎么变化”。

行为型共有 11 种,数量最多,也是最容易混淆的一组。

行为型模式总览

中文名英文名一句话意图题干关键词
职责链Chain of Responsibility让多个对象都有机会处理请求,请求沿链传递层层审批、向上提交、直到有人处理
命令Command将请求封装成对象请求对象、排队、日志、撤销
解释器Interpreter定义语言文法,并解释句子文法、终结符、非终结符、解释
迭代器Iterator顺序访问聚合对象元素,不暴露内部表示遍历、next、聚合对象
中介者Mediator用中介对象封装一组对象交互多对象交互、降低耦合、都找中介
备忘录Memento在不破坏封装前提下保存对象状态备份、恢复、快照
观察者Observer对象状态变化时通知所有依赖者一对多联动、订阅、自动通知
状态State对象内部状态改变时改变行为状态封装成类、不同状态不同行为
策略Strategy封装一组算法,使它们可互换算法族、方案切换、折扣策略
模板方法Template Method父类定义算法骨架,子类实现可变步骤算法骨架、模板填空、步骤延迟
访问者Visitor在不改变元素类的前提下增加操作visit、accept、数据与操作分离

职责链:请求沿链传递

职责链把多个处理者连成一条链。请求发送者只把请求交给链上的某个处理者,如果当前处理者不能处理,就继续向后传递,直到有人处理。

mermaid
flowchart LR
  Request["请假请求"] --> Leader["组长"]
  Leader -- "权限不足" --> Manager["部门经理"]
  Manager -- "权限不足" --> Director["总经理"]
  Director --> Done["处理完成"]

它的价值是降低发送者和多个接收者之间的耦合。发送者不需要知道谁最终处理,只需要把请求丢进链里。

考试关键词:层层审批、请求沿链传递、多个对象都有处理机会、不明确指定接收者。

命令:把请求封装成对象

命令模式把请求封装成对象。请求一旦成为对象,就可以被排队、记录、撤销、重做,也可以作为参数传递。

mermaid
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

解释器在软考中考得相对少,但需要记住关键词:文法、解释、终结符、非终结符。

迭代器:顺序访问聚合对象

迭代器提供一种方法顺序访问聚合对象中的各个元素,而不暴露内部表示。

mermaid
flowchart LR
  Aggregate["聚合对象"] --> Iterator["迭代器"]
  Iterator --> First["first()"]
  Iterator --> Next["next()"]
  Iterator --> Current["currentItem()"]

许多现代语言已内置迭代器接口,所以考试通常不会要求自己实现完整迭代器,但会考“顺序访问聚合对象”“不暴露内部结构”“next 方法”等关键词。

中介者:把网状交互变成中心协调

中介者用一个中介对象封装一系列对象的交互。原本对象之间两两通信,关系会变成复杂网状;引入中介者后,每个对象只需要与中介者交互。

mermaid
flowchart LR
  A["对象A"] <--> M["中介者"]
  B["对象B"] <--> M
  C["对象C"] <--> M
  D["对象D"] <--> M

它和代理模式的区别很重要:

对比项代理中介者
解决问题控制对某个对象的访问协调多个对象之间的交互
关系形态客户 -> 代理 -> 真实对象多个对象都与中介者通信
是否改变交互结构通常只是访问路径多一层改变多对象交互方式

题干如果强调“多个对象交互复杂,通过中心对象协调”,选中介者。

备忘录:保存状态以便恢复

备忘录在不破坏封装的前提下,捕获对象内部状态,并在对象之外保存,以便以后恢复。

mermaid
flowchart LR
  Originator["原发器\n当前状态"] --> Memento["备忘录\n保存状态"]
  Caretaker["管理者"] --> Memento
  Memento --> Originator

它的关键是“备份”和“恢复”。不是重新创建一个完整新对象,而是把需要恢复的状态保存起来。

观察者:一对多联动

观察者模式定义对象间一对多依赖。当一个对象状态变化时,所有依赖它的对象都会得到通知并自动更新。

mermaid
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

课程强调“注册/订阅”:观察者先注册到主题中,主题状态变化时再通知所有观察者。看到“发布订阅”“自动通知”“一对多联动”,选观察者。

例题

单选
一个对象状态变化时自动通知多个依赖对象,属于:
单选
希望将请求封装成对象,以支持排队、日志记录和撤销操作,适合使用:

自查要点

  1. 职责链为什么能降低请求发送者和处理者之间的耦合?
  2. 命令模式为什么能支持撤销和日志?
  3. 中介者和代理都加了一个对象,它们改变的关系有什么不同?
  4. 观察者模式中的注册、通知、更新分别对应什么?