观察者模式(Observer Pattern)是一种设计结构中最实用、最常见的行为模式之一。它的魅力不仅在于简洁的“一对多”事件推送能力,更在于它的解耦能力、模块协作设计、实时响应能力。
本篇作为 Day 6,将带你从理论、底层机制到真实工程项目实战,全方位、系统地掌握观察者模式,彻底吃透其设计价值。
观察者模式的核心,是在被观察者状态变化时通知所有关心它的对象,从而构建一个低耦合、响应式的通知机制。
class Subject {
public:
void attach(Observer* obs);
void detach(Observer* obs);
void notify();
};
class Observer {
public:
virtual void update() = 0;
};
✅ 示例:
button.onClick().connect([]() {
std::cout << "按钮被点击,弹窗显示!" << std::endl;
});
✅ 模块划分:
MarketDataFeed
:行情中心(Subject)ChartUI / Alarm / StrategyModel
:观察者观察者的关键,就是通过函数指针 / 回调函数 / lambda 表达式连接行为与状态变化。
void (*callback)(int);
callback = myHandler;
callback(123); // 执行
auto callback = [](int price) {
std::cout << "新价格:" << price << std::endl;
};
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 是观察者模式在现代 C++ 中的高效、安全实现。它将“通知发布者(Subject)”与“通知接收者(Observer)”的注册、解绑、调用机制封装得更加通用和安全。
signal
类似“事件总线”,可连接多个“响应槽(slot)”connect()
注册 slotoperator()
触发信号,自动调用所有 slot特性 | 说明 |
---|---|
自动解绑 | 支持 scoped_connection 、生命周期追踪(weak_ptr) |
多线程安全 | 所有操作加锁,适合多线程信号触发 |
返回值聚合器 | 可对多个 slot 的返回值做统一处理(例如返回第一个、合并结果) |
插槽灵活连接 | 支持函数、lambda、成员函数、functor 对象 |
boost::signals2::signal<void(int)> sig;
sig.connect([](int v) { std::cout << "值为:" << v << std::endl; });
sig(42); // 触发所有观察者响应
{
boost::signals2::scoped_connection conn = sig.connect(...);
// conn 析构自动解除绑定
} // 安全退出,不再触发此 slot
sig.connect(boost::bind(&Class::method, &obj, _1));
Boost.Signals2 的底层结构包含:
它解决了手写观察者中最容易出现的问题:
因此在现代 C++ 项目中,如果你需要一种安全、可维护、低耦合、线程友好的观察者实现方案,Boost.Signals2 是首选。
工业设备上连接温度传感器,当温度变化时,需要:
+--------------------+
| TemperatureSensor |
+--------------------+
| +addListener() | ← 注册观察者
| +removeListener() |
| +updateTemp() | ← 状态变化
| +notify() |
+--------------------+
↓
多个监听回调函数(Slot)
#include
#include
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
if (t > 100) observerA();
else observerB();
“我们项目中大量使用观察者机制来进行模块间解耦,比如设备数据变化后推送到 UI、日志、预警等模块。为了安全性与性能,我们使用了 Boost.Signals2,实现了自动连接管理与线程安全的广播机制,同时通过 lambda 与 bind 配合,保持代码灵活、结构清晰。”
✅ 加分关键词:事件推送 / 多模块联动 / 自动解绑 / 异步广播 / 回调链路
模块要素 | 说明 |
---|---|
Subject | 状态持有者,触发变化 |
Observer | 回调函数实体,响应变化 |
通知机制 | connect → 回调列表 → notify 调用 |
解耦点 | 无需知道观察者是谁,只要通知 |
实现方式 | 函数指针 / lambda / bind / signal |
✅ 一句话背诵版:
“观察者模式通过回调机制建立一对多解耦通道,实现状态联动与模块协作。”
策略模式(Strategy Pattern)实战详解:在支付系统、路径规划、压缩算法中优雅切换策略。