一、传统观察者 vs 现代写法
传统:
struct Observer {
virtual void onEvent(const Event&) = 0;
};
class Subject {
std::vector<Observer*> observers_;
public:
void attach(Observer* o) { observers_.push_back(o); }
void notify(const Event& e) {
for (auto* o : observers_) o->onEvent(e);
}
};
问题:Observer 必须继承虚基类,生命周期由 Subject 外部管理(悬垂指针风险)。
现代写法:
class EventBus {
std::vector<std::function<void(const Event&)>> handlers_;
public:
// 接受 lambda、函数指针、任何可调用对象
template <typename F>
void subscribe(F&& handler) {
handlers_.push_back(std::forward<F>(handler));
}
void fire(const Event& event) {
for (auto& h : handlers_) {
h(event);
}
}
};
// 使用——不需要继承任何东西
EventBus bus;
bus.subscribe([](const Event& e) {
std::cout << "received: " << e.type << "\n";
});
Server server;
server.on_connect([&bus](ConnectionPtr conn) {
bus.fire(Event{"connected"});
});
二、生命周期管理
现代观察者模式的最大问题:订阅者的生命周期。如果订阅者先于 EventBus 销毁,但订阅 lambda 捕获了订阅者的 this 指针,EventBus 触发事件时就是 Use-After-Free。
解决方案:用 shared_ptr + weak_ptr:
class Subscriber : public std::enable_shared_from_this<Subscriber> {
public:
void subscribe(EventBus& bus) {
auto weak_self = weak_from_this(); // C++17
bus.subscribe([weak_self](const Event& e) {
if (auto self = weak_self.lock()) {
self->handleEvent(e); // Subscriber 还活着,安全处理
}
// 如果 Subscriber 已销毁,什么都不做
});
}
void handleEvent(const Event& e) { /* ... */ }
};