观察者模式(Observer Pattern)是一种设计结构中最实用、最常见的行为模式之一。它的魅力不仅在于简洁的"一对多"事件推送能力,更在于它的解耦能力、模块协作设计、实时响应能力。
本篇作为 Day 6,将带你从理论、底层机制到真实工程项目实战,全方位、系统地掌握观察者模式,彻底吃透其设计价值。
一、重新理解观察者模式的本质
✅ 一句话总结:
观察者模式的核心,是在被观察者状态变化时通知所有关心它的对象 ,从而构建一个低耦合、响应式的通知机制。
📌 抽象结构:
cpp
class Subject {
public:
void attach(Observer* obs);
void detach(Observer* obs);
void notify();
};
class Observer {
public:
virtual void update() = 0;
};
🎯 优点:
- 一对多广播机制,通知多模块
- 实现了"订阅/发布"架构模型
- 观察者动态添加移除,系统更灵活
❗ 本质关键:
- 状态变更感知 + 自动联动更新
- 利用回调函数机制(函数指针 / lambda)实现通知解耦
二、现实中典型的观察者模式场景(高频 + 好记 + 实战)

🌟 1. GUI 事件响应系统(经典)
- 鼠标点击按钮 → 所有监听该按钮事件的 UI 模块立刻响应
✅ 示例:
cpp
button.onClick().connect([]() {
std::cout << "按钮被点击,弹窗显示!" << std::endl;
});
🌟 2. 实时行情推送系统(金融/交易所)
- 价格更新后 → 各个终端(交易页面、预警模块、图表组件)即时响应
✅ 模块划分:
MarketDataFeed
:行情中心(Subject)ChartUI / Alarm / StrategyModel
:观察者
🌟 3. 硬件驱动数据采集(IoT / 医疗监护)
- 心率变化 → 推送给监护仪屏幕、记录系统、告警系统
🌟 4. 游戏开发:对象状态广播
- 血量变化 → 渲染模块、AI判断模块、音效模块需同时更新
🌟 5. 插件系统事件通知
- IDE 插件监听工程加载事件、文件保存事件等
三、观察者模式的核心:回调函数机制
观察者的关键,就是通过函数指针 / 回调函数 / lambda 表达式连接行为与状态变化。
✅ 1. 函数指针的基本形式
cpp
void (*callback)(int);
callback = myHandler;
callback(123); // 执行
✅ 2. lambda 表达式(现代写法)
cpp
auto callback = [](int price) {
std::cout << "新价格:" << price << std::endl;
};
✅ 3. std::function + std::bind(成员函数回调)
cpp
class Alarm {
public:
void trigger(int v) { std::cout << "触发报警:" << v << std::endl; }
};
Alarm alarm;
std::function<void(int)> cb = std::bind(&Alarm::trigger, &alarm, std::placeholders::_1);
cb(90);
这些函数式调用,正是观察者通知机制的底层实现核心。
四:Boost.Signals2 的使用原理与机制
Boost.Signals2 是观察者模式在现代 C++ 中的高效、安全实现。它将"通知发布者(Subject)"与"通知接收者(Observer)"的注册、解绑、调用机制封装得更加通用和安全。
✅ 基本原理:
signal<T>
类似"事件总线",可连接多个"响应槽(slot)"connect()
注册 slotoperator()
触发信号,自动调用所有 slot
✅ 特点分析:
特性 | 说明 |
---|---|
自动解绑 | 支持 scoped_connection 、生命周期追踪(weak_ptr) |
多线程安全 | 所有操作加锁,适合多线程信号触发 |
返回值聚合器 | 可对多个 slot 的返回值做统一处理(例如返回第一个、合并结果) |
插槽灵活连接 | 支持函数、lambda、成员函数、functor 对象 |
✅ 例子说明:
cpp
boost::signals2::signal<void(int)> sig;
sig.connect([](int v) { std::cout << "值为:" << v << std::endl; });
sig(42); // 触发所有观察者响应
✅ 自动解绑:
cpp
{
boost::signals2::scoped_connection conn = sig.connect(...);
// conn 析构自动解除绑定
} // 安全退出,不再触发此 slot
✅ 成员函数绑定:
cpp
sig.connect(boost::bind(&Class::method, &obj, _1));
Boost.Signals2 的底层结构包含:
- slot 链表容器:存储所有观察者
- 线程锁保护:对 connect/emit 操作加锁
- 断开机制:支持连接手动断开、生命周期关联解绑
它解决了手写观察者中最容易出现的问题:
- 悬空指针访问
- 多线程数据竞争
- 连接管理混乱
因此在现代 C++ 项目中,如果你需要一种安全、可维护、低耦合、线程友好的观察者实现方案,Boost.Signals2 是首选。
五、项目实战:构建一个"传感器驱动 + 多模块响应系统"
📌 需求背景:
工业设备上连接温度传感器,当温度变化时,需要:
- 屏幕显示实时温度
- 超过阈值时报警
- 自动记录进系统日志
🎯 类结构图:
+--------------------+
| TemperatureSensor |
+--------------------+
| +addListener() | ← 注册观察者
| +removeListener() |
| +updateTemp() | ← 状态变化
| +notify() |
+--------------------+
↓
多个监听回调函数(Slot)
✅ C++ 实现(使用 Boost.Signals2):
cpp
#include <iostream>
#include <boost/signals2.hpp>
class TemperatureSensor {
public:
boost::signals2::signal<void(float)> onTempChanged;
void updateTemp(float newTemp) {
std::cout << "[Sensor] 当前温度:" << newTemp << std::endl;
onTempChanged(newTemp); // 触发信号,通知所有观察者
}
};
class LCDDisplay {
public:
void show(float t) {
std::cout << "[LCD] 显示温度:" << t << std::endl;
}
};
class AlarmModule {
public:
void check(float t) {
if (t > 80)
std::cout << "[Alarm] 温度过高,发出警报!" << std::endl;
}
};
class Logger {
public:
void log(float t) {
std::cout << "[Log] 记录温度值:" << t << std::endl;
}
};
int main() {
TemperatureSensor sensor;
LCDDisplay lcd;
AlarmModule alarm;
Logger logger;
sensor.onTempChanged.connect([&](float t){ lcd.show(t); });
sensor.onTempChanged.connect([&](float t){ alarm.check(t); });
sensor.onTempChanged.connect([&](float t){ logger.log(t); });
sensor.updateTemp(65.0);
sensor.updateTemp(88.2);
return 0;
}
✅ 输出示例:
[Sensor] 当前温度:65
[LCD] 显示温度:65
[Log] 记录温度值:65
[Sensor] 当前温度:88.2
[LCD] 显示温度:88.2
[Alarm] 温度过高,发出警报!
[Log] 记录温度值:88.2
六、观察者模式的扩展与变种
✅ 延迟通知 vs 立即通知
- 有些系统不立即通知,而是打包合并,异步发送 → 对应"批量广播机制"
✅ 支持过滤的观察者(按条件触发)
cpp
if (t > 100) observerA();
else observerB();
✅ 支持优先级注册
- 有些响应函数必须先执行,可加入优先级队列(boost 支持插槽分组)
七、面试与复述技巧
"我们项目中大量使用观察者机制来进行模块间解耦,比如设备数据变化后推送到 UI、日志、预警等模块。为了安全性与性能,我们使用了 Boost.Signals2,实现了自动连接管理与线程安全的广播机制,同时通过 lambda 与 bind 配合,保持代码灵活、结构清晰。"
✅ 加分关键词:事件推送 / 多模块联动 / 自动解绑 / 异步广播 / 回调链路
八、总结记忆要点
模块要素 | 说明 |
---|---|
Subject | 状态持有者,触发变化 |
Observer | 回调函数实体,响应变化 |
通知机制 | connect → 回调列表 → notify 调用 |
解耦点 | 无需知道观察者是谁,只要通知 |
实现方式 | 函数指针 / lambda / bind / signal |
✅ 一句话背诵版:
"观察者模式通过回调机制建立一对多解耦通道,实现状态联动与模块协作。"
明日预告:Day 7
策略模式(Strategy Pattern)实战详解:在支付系统、路径规划、压缩算法中优雅切换策略。