行为型设计模式(GoF 11)
更新时间:2026-08-24。行为型模式关注对象之间如何交互、如何分配职责,处理的是运行时的协作流程与算法组织。
问题与主线
对象协作最朴素的方式是直接 a.foo(); b.bar(); 硬编码流程。这带来:调用方与实现方深度耦合、流程写死难扩展、对象间互相直接依赖。行为型模式的共同目标:把"交互/算法"从具体对象中解耦,让协作规则可以独立变化、复用。
十一种模式全景
| 模式 | 核心问题 | 关键思想 |
|---|---|---|
| 策略 Strategy | 运行时切换算法 | 算法封装成对象,可替换 |
| 观察者 Observer | 状态变化通知依赖者 | 订阅/发布,一对多 |
| 模板方法 Template Method | 骨架固定、步骤可变 | 父类定流程,子类实现步骤 |
| 状态 State | 状态改变行为也变 | 行为委托给状态对象 |
| 命令 Command | 请求封装成对象 | 请求可排队、可撤销、可记录 |
| 职责链 Chain | 多个处理者逐个尝试 | 请求沿链传递直到被处理 |
| 迭代器 Iterator | 封装遍历 | 统一遍历接口,隐藏内部结构 |
| 中介者 Mediator | 集中管理交互 | 对象间不直接通信,经中介者 |
| 备忘录 Memento | 保存并恢复状态 | 状态快照,可回滚 |
| 解释器 Interpreter | 自定义语法 | 语法树 + 递归求值 |
| 访问者 Visitor | 对元素施加新操作 | 操作与数据结构分离 |
1. 策略 Strategy
问题:同一操作有多种算法,且运行时切换(排序算法、压缩算法、支付方式、路由策略)。
朴素方案缺陷:if (type==A) ... else if (type==B) 大分支,新增算法要改业务类(违反 OCP)。
模式方案:算法封装成策略对象,上下文持有一个策略、可替换。
class SortStrategy {
public:
virtual ~SortStrategy() = default;
virtual std::vector<int> sort(std::vector<int> v) = 0;
};
class QuickSort : public SortStrategy {
public:
std::vector<int> sort(std::vector<int> v) override { /* ... */ return v; }
};
class MergeSort : public SortStrategy {
public:
std::vector<int> sort(std::vector<int> v) override { /* ... */ return v; }
};
class Sorter {
public:
explicit Sorter(std::unique_ptr<SortStrategy> s) : strategy_(std::move(s)) {}
void setStrategy(std::unique_ptr<SortStrategy> s) { strategy_ = std::move(s); }
std::vector<int> run(std::vector<int> v) { return strategy_->sort(std::move(v)); }
private:
std::unique_ptr<SortStrategy> strategy_;
};
Sorter s(std::make_unique<QuickSort>());
auto r1 = s.run({3,1,2});
s.setStrategy(std::make_unique<MergeSort>()); // 运行时换算法
auto r2 = s.run({3,1,2});适用:算法族可替换、需运行时切换。常配合工厂(创建策略)与参数对象。
2. 观察者 Observer
问题:一个对象状态变化,多个依赖者要同步更新(订阅、事件、MVC 的 Model→View)。
朴素方案缺陷:被观察者直接持有所有依赖者,新增观察者要改被观察者(违反 OCP),且形成强耦合。
模式方案:被观察者维护观察者列表,变化时广播通知。
class Observer {
public:
virtual ~Observer() = default;
virtual void update(const std::string& event) = 0;
};
class Subject {
public:
void attach(Observer* o) { observers_.push_back(o); }
void notify(const std::string& event) {
for (auto* o : observers_) o->update(event); // 一对多广播
}
private:
std::vector<Observer*> observers_;
};
class EmailAlert : public Observer {
public:
void update(const std::string& e) override { /* 发邮件 */ }
};
class LogAlert : public Observer {
public:
void update(const std::string& e) override { /* 记日志 */ }
};
Subject priceFeed;
EmailAlert email; LogAlert log;
priceFeed.attach(&email);
priceFeed.attach(&log);
priceFeed.notify("price_up"); // 两个观察者都被通知适用:一对多联动、事件/消息发布订阅。注意:观察者顺序无保证、可能循环通知,需防重入。
3. 模板方法 Template Method
问题:算法骨架固定(如"煮饮料":烧水→冲泡→倒杯→加料),但某几步因类型而异。
朴素方案缺陷:把相同流程复制到每个子类,重复代码多、改流程要改所有子类。
模式方案:父类定义算法骨架(调用抽象步骤),子类只实现可变步骤。
class Beverage {
public:
// 模板方法:骨架固定,不可被子类覆盖
void make() {
boilWater();
brew(); // 抽象步骤,子类实现
pourInCup();
addCondiments(); // 抽象步骤,子类实现(可挂钩)
}
virtual ~Beverage() = default;
protected:
virtual void brew() = 0;
virtual void addCondiments() = 0;
private:
void boilWater() { /* 固定 */ }
void pourInCup() { /* 固定 */ }
};
class Tea : public Beverage {
protected:
void brew() override { /* 泡茶叶 */ }
void addCondiments() override { /* 加柠檬 */ }
};
class Coffee : public Beverage {
protected:
void brew() override { /* 煮咖啡 */ }
void addCondiments() override { /* 加糖奶 */ }
};适用:流程骨架稳定、个别步骤可变。是"控制反转"的雏形——父类调用子类方法。
4. 状态 State
问题:对象行为随内部状态改变而改变(订单状态、TCP 连接状态、玩家状态),且状态迁移复杂。
朴素方案缺陷:一个类里堆 if (state==A) ... else if (state==B),状态多了类膨胀、改一个状态要动整个类。
模式方案:每个状态一个类,行为委托给当前状态对象,状态切换就是换对象。
class OrderContext; // 前向声明
class OrderState {
public:
virtual ~OrderState() = default;
virtual std::string current() = 0;
virtual void next(OrderContext& ctx) = 0;
};
class OrderContext {
public:
void setState(std::shared_ptr<OrderState> s) { state_ = std::move(s); }
void advance() { state_->next(*this); }
std::string state() const { return state_->current(); }
private:
std::shared_ptr<OrderState> state_;
};
// 状态实现:各自定义迁移
class PaidState; class ShippedState;
class NewState : public OrderState {
public:
std::string current() override { return "new"; }
void next(OrderContext& ctx) override { ctx.setState(std::make_shared<PaidState>()); }
};
class PaidState : public OrderState {
public:
std::string current() override { return "paid"; }
void next(OrderContext& ctx) override { ctx.setState(std::make_shared<ShippedState>()); }
};
class ShippedState : public OrderState {
public:
std::string current() override { return "shipped"; }
void next(OrderContext&) override { /* 终态 */ }
};适用:状态多且迁移复杂、希望状态迁移集中且可扩展。对比大 switch,新增状态只需新类。
5. 命令 Command
问题:把请求(操作)封装成对象,以便排队、记录日志、支持撤销/重做(编辑器、事务、任务队列)。
朴素方案缺陷:操作直接写在调用处,无法入队、无法统一撤销、无法序列化。
模式方案:每个操作一个命令对象,统一 execute()(及可选 undo())。
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0;
virtual void undo() = 0;
};
class TextEditor {
public:
void insert(const std::string& t) { text_ += t; }
void remove(size_t n) { text_.erase(text_.size() - n); }
std::string text() const { return text_; }
private:
std::string text_;
};
class InsertCommand : public Command {
public:
InsertCommand(TextEditor& e, std::string t) : editor_(e), text_(std::move(t)) {}
void execute() override { editor_.insert(text_); }
void undo() override { editor_.remove(text_.size()); }
private:
TextEditor& editor_;
std::string text_;
};
// 命令历史:支持撤销
std::vector<std::unique_ptr<Command>> history;
auto cmd = std::make_unique<InsertCommand>(ed, "hello");
cmd->execute(); history.push_back(std::move(cmd));
history.back()->undo(); // 撤销适用:操作需入队/撤销/日志/宏录制。命令对象也可序列化后走消息队列(分布式命令)。
6. 职责链 Chain of Responsibility
问题:一个请求可能有多个候选处理者,但谁处理取决于条件(日志级别、请求过滤链、审批流程),且顺序可配置。
朴素方案缺陷:调用方写一长串 if (能处理) else 传给下一个,新处理者要改调用方。
模式方案:处理者组成链,每个处理者要么处理、要么传给后继。
class Handler {
public:
void setNext(std::shared_ptr<Handler> n) { next_ = std::move(n); }
virtual void handle(int level) {
if (canHandle(level)) process(level);
else if (next_) next_->handle(level); // 传链
// 无后继则链尾
}
virtual ~Handler() = default;
protected:
virtual bool canHandle(int level) = 0;
virtual void process(int level) = 0;
std::shared_ptr<Handler> next_;
};
class InfoHandler : public Handler {
protected:
bool canHandle(int l) override { return l <= 1; }
void process(int l) override { /* info */ }
};
class ErrorHandler : public Handler {
protected:
bool canHandle(int l) override { return l >= 3; }
void process(int l) override { /* error */ }
};
auto info = std::make_shared<InfoHandler>();
auto err = std::make_shared<ErrorHandler>();
info->setNext(err); // 组成链
info->handle(5); // Info 不能处理 → 传给 Error → 处理适用:处理者顺序可变、请求需按优先级/条件分派。
7-11. 迭代器 / 中介者 / 备忘录 / 解释器 / 访问者(简)
| 模式 | 场景 | 要点 |
|---|---|---|
| 迭代器 | 遍历集合但不暴露内部结构 | 统一 begin()/end()/next() 接口;C++ STL 已内置,自定义迭代器配合 range-for |
| 中介者 | 多个对象直接互相引用、通信混乱 | 集中到中介者,对象只与中介者通信(聊天室、航班调度) |
| 备忘录 | 保存状态用于回滚/撤销 | 快照对象 + 原发器管理;注意深拷贝与内存开销 |
| 解释器 | 自定义语言/规则求值 | 语法树 + 递归求值(SQL 解析、正则、表达式引擎) |
| 访问者 | 对一组对象施加新操作,不改对象类 | 操作集中在访问者,accept(visitor) 双分派;新增操作方便、新增类型麻烦 |
现代实践中,迭代器基本由语言标准库承载;中介者常被事件总线/消息中间件取代;解释器多用现成解析库(flex/bison、antlr);访问者在结构稳定时很强大,结构频繁变化时慎用。
十一种模式横向对比:到底好在哪里
行为型的 11 种解决的是不同侧面的"交互与职责分配"。它们最易混淆的是三组:策略/状态/模板方法(都涉及"算法/行为")、观察者/中介者/职责链(都涉及"通知/分发")、命令/备忘录(都涉及"操作与撤销")。先看最容易混的策略、状态、模板方法:

再看"通知/分发"三兄弟,它们在协作方向上截然不同:

对比表
| 模式 | 封装/解耦什么 | 协作方向 | 好在哪里(相对朴素写法) | 最易混淆对手 |
|---|---|---|---|---|
| Strategy | 算法族可替换 | 客户端→策略 | 消灭 if(type) 大分支;加算法=新类,业务零改 | State |
| Observer | 一对多联动 | 被观察者→观察者 | 加观察者=新类零改动;被观察者不持有具体依赖 | Mediator |
| Template Method | 固定骨架+可变步骤 | 父类→子类钩子 | 复用骨架、消除重复;改流程只改父类一处 | Strategy |
| State | 状态决定行为+迁移 | 上下文→状态对象 | 消灭状态 switch;加状态=新类,迁移集中 | Strategy |
| Command | 请求封装成对象 | 调用方→命令→接收者 | 可入队/撤销/日志/宏;操作与执行解耦 | Memento |
| Chain of Responsibility | 处理者顺序分发 | 请求沿链传递 | 加处理者=插链节;解耦"谁处理" | Observer |
| Iterator | 遍历细节 | 客户端→集合 | 隐藏内部结构;STL 已内置 | Composite |
| Mediator | 对象间通信 | 各对象→中介 | 拆网状为星状;对象只知中介 | Observer / Facade |
| Memento | 状态快照回滚 | 原发器↔备忘录 | 支持撤销且不破坏封装 | Command |
| Interpreter | 语法求值 | 客户端→语法树 | 语言规则可扩展;现多用 antlr 等 | — |
| Visitor | 结构上加操作 | 客户端→元素→访问者 | 加操作=新访问者不改元素;双分派 | Iterator |
关键辨析
- 策略 vs 状态:最容易混。Strategy 是"客户端主动选择算法",算法之间互不相识、无迁移;State 是"状态自己决定下一状态",状态之间会互相迁移。换算法用 Strategy,状态机用 State。
- 策略 vs 模板方法:Strategy 用组合、算法整体替换;Template Method 用继承、骨架固定、只覆盖部分步骤。需要复用整个流程框架→模板方法;只换某一算法→策略。
- 观察者 vs 中介者 vs 职责链:Observer 是一对多(发布广播);Mediator 是多对多收敛(网状→星状);Chain 是一对一逐级(沿链传递)。要广播用观察者、要解耦网状引用用中介者、要按顺序尝试处理用职责链。
- 命令 vs 备忘录:两者都服务"撤销",但机制不同——Command 通过记录逆操作撤销(执行/反执行);Memento 通过保存状态快照回滚(存状态/恢复)。可组合:命令历史里配合备忘录保存快照。
- 观察者 vs 访问者:Observer 是"状态变化通知所有依赖者";Visitor 是"结构稳定时对元素施加新操作"。一个靠订阅、一个靠双分派。
- 一句话定位:Strategy 换算法、State 随状态、Template 定骨架、Observer 做广播、Mediator 收敛通信、Chain 逐级分发、Command 留撤销、Memento 存快照、Iterator 藏遍历、Interpreter 解语法、Visitor 加操作——先问"我要解耦的是算法、状态、通知、还是职责分配",答案自现。
决策速查

一句话总结:行为型模式把"对象怎么协作、算法怎么组织"从硬编码中解放出来——策略换算法、观察者做联动、模板方法定骨架、状态改行为、命令留撤销、职责链排队处理,核心是解耦交互与职责分配。