文章目录
前言
搞软件开发,对象间怎么高效"唠嗑"是个核心问题。想象一下,一个对象状态变了,怎么让那些依赖它的兄弟们自动知道并更新?观察者模式(Observer Pattern)就是为解决这个痛点而生的行为设计模式。它定义了一对多的依赖关系,让一个对象(主题)状态变化时,所有依赖它的对象(观察者)都能自动收到通知并刷新。
这模式在现代软件里应用贼广,比如:
- GUI框架里的事件处理
- 消息队列和事件总线
- 订阅-发布系统
- 实时数据监控和更新
这篇猫哥就深入聊聊C++里观察者模式的门道,从基础定义、传统实现到高级玩法,配上硬核代码示例,让你彻底搞懂怎么玩转它。

观察者模式的核心骨架
观察者模式说白了就这四大金刚:
- 主题(Subject):也叫被观察者或发布者。管着一群观察者小弟,负责招人(注册)、踢人(移除)和发通知。
- 观察者(Observer):也叫订阅者。定了规矩,主题通知来了得知道怎么接。
- 具体主题(Concrete Subject):主题的实干派。自己维护状态,状态一变就吆喝通知观察者。
- 具体观察者(Concrete Observer):观察者的行动派。接到通知后知道该干嘛,更新自己状态。
传统实现:手把手搭个观察者
先把架子搭好(抽象接口)
cpp
// observer.h
#ifndef OBSERVER_H
#define OBSERVER_H
#include <string>
#include <vector>
#include <memory>
// 观察者接口:定个接收消息的规矩
class Observer {
public:
virtual ~Observer() = default;
virtual void update(const std::string& message) = 0; // 纯虚函数,必须实现
};
// 主题接口:管小弟的招数
class Subject {
public:
virtual ~Subject() = default;
virtual void attach(std::shared_ptr<Observer> observer) = 0; // 收小弟
virtual void detach(std::shared_ptr<Observer> observer) = 0; // 踢小弟
virtual void notify(const std::string& message) = 0; // 发通知
};
#endif // OBSERVER_H
实干派登场(具体实现)
cpp
// concrete_subject.h
#include "observer.h"
#include <mutex>
class ConcreteSubject : public Subject {
private:
std::string state_; // 核心状态
std::vector<std::weak_ptr<Observer>> observers_; // 用weak_ptr防循环引用
mutable std::mutex mutex_; // 线程安全必备
public:
// 收小弟(线程安全)
void attach(std::shared_ptr<Observer> observer) override {
std::lock_guard<std::mutex> lock(mutex_);
observers_.push_back(observer);
}
// 踢小弟(线程安全,清理失效观察者)
void detach(std::shared_ptr<Observer> observer) override {
std::lock_guard<std::mutex> lock(mutex_);
observers_.erase(
std::remove_if(observers_.begin(), observers_.end(),
[&observer](const std::weak_ptr<Observer>& w) {
auto s = w.lock();
return !s || s.get() == observer.get(); // 找失效或指定观察者
}),
observers_.end());
}
// 发通知(线程安全,边通知边清理僵尸)
void notify(const std::string& message) override {
std::lock_guard<std::mutex> lock(mutex_);
observers_.erase(
std::remove_if(observers_.begin(), observers_.end(),
[message](const std::weak_ptr<Observer>& w) {
auto s = w.lock();
if (s) {
s->update(message); // 通知有效观察者
return false; // 保留
}
return true; // 标记失效的待清理
}),
observers_.end());
}
// 改状态,顺便吆喝
void setState(const std::string& state) {
state_ = state;
notify("State changed to: " + state_); // 状态变,通知到!
}
};
// concrete_observer.h
#include "observer.h"
#include <iostream>
class ConcreteObserver : public Observer {
private:
std::string name_;
int notificationCount_ = 0; // 计数收到几次通知
public:
explicit ConcreteObserver(const std::string& name) : name_(name) {}
// 接到通知后的动作
void update(const std::string& message) override {
notificationCount_++;
std::cout << "Observer " << name_ << " received: " << message << " (Total: " << notificationCount_ << ")" << std::endl;
}
};
跑起来看看效果
cpp
#include "concrete_subject.h"
#include "concrete_observer.h"
#include <memory>
int main() {
// 老大登场
auto subject = std::make_shared<ConcreteSubject>();
// 两个吃瓜小弟
auto observer1 = std::make_shared<ConcreteObserver>("Observer1");
auto observer2 = std::make_shared<ConcreteObserver>("Observer2");
// 收小弟入伙
subject->attach(observer1);
subject->attach(observer2);
// 老大状态变了,小弟们收通知!
subject->setState("Active");
subject->setState("Inactive");
// 踢走一个
subject->detach(observer1);
// 再变状态,只剩一个收通知
subject->setState("Processing");
return 0;
}
高级玩法:更强大的观察者模式
传统模式够用但不够酷。复杂系统里,得整点更强大的功能:
- 多事件类型:不同事发不同通知
- 事件驱动:基于事件灵活通知
- 版本追踪:状态变化有迹可循
- 线程安全:多线程环境稳如狗
事件驱动引擎
cpp
// event_manager.h
#ifndef EVENT_MANAGER_H
#define EVENT_MANAGER_H
#include <unordered_map>
#include <vector>
#include <memory>
#include <mutex>
#include <string>
// 定义有啥事件
enum class EventType {
STATE_CHANGE, // 状态变
DATA_UPDATE, // 数据更新
SYSTEM_ALERT, // 系统告警
USER_ACTION // 用户操作
};
// 事件包裹里装啥
struct EventData {
EventType type;
std::string message;
std::unordered_map<std::string, std::string> properties; // 额外属性
EventData(EventType t, const std::string& msg) : type(t), message(msg) {}
};
// 事件观察者:接事件通知
class EventObserver {
public:
virtual ~EventObserver() = default;
virtual void onEvent(const EventData& event) = 0;
};
// 事件管家:管事件分发
class EventManager {
private:
std::unordered_map<EventType, std::vector<std::shared_ptr<EventObserver>>> observers_; // 按事件类型存观察者
mutable std::mutex mutex_; // 锁住,线程安全
public:
void subscribe(EventType type, std::shared_ptr<EventObserver> observer); // 订阅事件
void unsubscribe(EventType type, std::shared_ptr<EventObserver> observer); // 取消订阅
void notify(const EventData& event); // 发事件通知
};
#endif // EVENT_MANAGER_H
智能主题(传统+事件双修)
cpp
// smart_subject.h
#ifndef SMART_SUBJECT_H
#define SMART_SUBJECT_H
#include "observer.h"
#include "event_manager.h"
#include <string>
#include <memory>
#include <chrono>
#include <mutex>
// 智能主题:兼容传统观察者 + 事件驱动
class SmartSubject : public Subject, public std::enable_shared_from_this<SmartSubject> {
private:
std::string state_; // 状态
int version_ = 0; // 状态版本号
std::shared_ptr<EventManager> eventManager_; // 事件管家
std::chrono::steady_clock::time_point lastUpdate_; // 上次更新时间
std::vector<std::weak_ptr<Observer>> traditionalObservers_; // 传统小弟
mutable std::mutex observerMutex_; // 传统小弟的锁
public:
SmartSubject(); // 构造
~SmartSubject() = default;
// 传统接口:收/踢小弟, 发通知
void attach(std::shared_ptr<Observer> observer) override;
void detach(std::shared_ptr<Observer> observer) override;
void notify(const std::string& message) override;
// 智能接口:设状态,拿状态/版本
void setState(const std::string& state);
std::string getState() const { return state_; }
int getVersion() const { return version_; }
// 事件驱动:触发事件
void triggerEvent(EventType type, const std::string& message);
};
#endif // SMART_SUBJECT_H
智能观察者(双接口兼容)
cpp
// smart_observer.h
#ifndef SMART_OBSERVER_H
#define SMART_OBSERVER_H
#include "observer.h"
#include "event_manager.h"
#include <string>
#include <iostream>
// 智能观察者:能接传统通知,也能接事件
class SmartObserver : public Observer, public EventObserver, public std::enable_shared_from_this<SmartObserver> {
private:
std::string name_;
int notificationCount_ = 0; // 通知计数
public:
explicit SmartObserver(const std::string& name);
~SmartObserver() = default;
// 传统通知
void update(const std::string& message) override;
// 事件通知
void onEvent(const EventData& event) override;
// 查户口
std::string getName() const { return name_; }
int getNotificationCount() const { return notificationCount_; }
};
#endif // SMART_OBSERVER_H
高级模式实战演示
cpp
#include "smart_subject.h"
#include "smart_observer.h"
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
int main() {
std::cout << "=== C++高级观察者模式实战 ===" << std::endl;
// 老大升级成智能主题
auto subject = std::make_shared<SmartSubject>();
// 三个智能小弟
auto observer1 = std::make_shared<SmartObserver>("Observer1");
auto observer2 = std::make_shared<SmartObserver>("Observer2");
auto observer3 = std::make_shared<SmartObserver>("Observer3");
// 传统方式收小弟1和2
subject->attach(observer1);
subject->attach(observer2);
std::cout << "\n--- 测试传统小弟 ---" << std::endl;
subject->setState("Active"); // 状态变,传统小弟收通知
std::this_thread::sleep_for(std::chrono::milliseconds(100));
subject->setState("Processing");
// 搞个事件管家,让小弟2订阅状态变化,小弟3订阅系统告警
auto eventManager = std::make_shared<EventManager>();
eventManager->subscribe(EventType::STATE_CHANGE, observer2);
eventManager->subscribe(EventType::SYSTEM_ALERT, observer3);
std::cout << "\n--- 测试事件驱动 ---" << std::endl;
subject->triggerEvent(EventType::SYSTEM_ALERT, "System maintenance scheduled"); // 发事件,小弟3响应
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// 踢走小弟1
std::cout << "\n--- 测试踢人 ---" << std::endl;
subject->detach(observer1);
subject->setState("Inactive"); // 状态变,只剩小弟2收通知
// 看看谁收到多少通知
std::cout << "\n--- 战绩统计 ---" << std::endl;
std::cout << observer1->getName() << " 收到 " << observer1->getNotificationCount() << " 条" << std::endl;
std::cout << observer2->getName() << " 收到 " << observer2->getNotificationCount() << " 条" << std::endl;
std::cout << observer3->getName() << " 收到 " << observer3->getNotificationCount() << " 条" << std::endl;
return 0;
}
观察者模式的江湖地位:利与弊
独门优势
- 解耦大师:主题和观察者各玩各的,内部细节互不干扰。
- 广播高手:主题一声吼,所有小弟都能听到,不用管谁是谁。
- 实时先锋:状态一变,通知秒到,数据一致性妥妥的。
- 灵活多变:运行时想加小弟、踢小弟,随心所欲。
- 遵守开闭:加新类型的小弟?主题代码动都不用动。
江湖险恶(缺点)
- 性能刺客:小弟太多,挨个通知一圈,时间耗不起。
- 循环依赖坑:主题和小弟相互引用没处理好,内存泄漏等着你。
- 顺序靠不住:通知顺序?看天(实现)!需要特定顺序得自己控。
- 调试迷宫:通知自动触发,出问题时追踪调用链像走迷宫。
啥时候该用它?
这模式最适合这些场子:
- 一拖N关系:一个对象状态变,N个对象得跟着变。
- 广播大喇叭:需要广而告之,不用知道具体谁在听。
- 解耦是王道:不想让消息发送方和接收方绑太死,方便扩展维护。
- 动态增减员:系统运行时需要灵活加人或减人。
猫哥结语
观察者模式绝对是对象间通信的利器,用好了能让代码灵活又解耦。在C++里玩转它,关键注意几点:
- 内存江湖险恶 :
shared_ptr和weak_ptr用好,避免内存泄漏这个江湖大敌。 - 多线程要稳 :锁(
mutex)是保护小弟列表和通知过程的必备铠甲。 - 事件设计要巧:高级玩法里,事件类型和数据结构设计好了,扩展性才强。
- 性能瓶颈得防:小弟成千上万?考虑异步通知、批量通知这些优化大招。
通过这篇长文和硬核代码,观察者模式从基础到进阶的门道应该都摸清了。下次在项目里遇到对象间需要高效"通风报信",就大胆用上它吧!