1. 模式定义
观察者模式(Observer Pattern)是一种行为型设计模式,定义了对象间的一对多依赖关系。当一个对象(被观察者/主题)状态改变时,所有依赖它的对象(观察者)都会自动收到通知并更新。该模式广泛应用于事件处理系统、GUI组件交互和实时数据监控等场景。
2. 核心思想
解耦:将主题与观察者解耦,使它们可以独立变化
动态订阅:支持观察者随时加入/退出通知列表
自动传播:状态变化时自动触发通知机制
3. 模式结构
关键角色:
-
Subject(主题接口)
- 维护观察者列表
- 提供注册/注销方法
- 定义通知方法
notify()
-
ConcreteSubject(具体主题)
- 存储具体状态数据
- 状态改变时触发通知
-
Observer(观察者接口)
- 定义更新接口
update()
- 定义更新接口
-
ConcreteObserver(具体观察者)
- 实现具体的更新逻辑
4. C++实现示例(气象监测系统)
完整代码实现
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory> // 智能指针支持
// 主题接口 --------------------------------------------------
class WeatherStation; // 前向声明
class Observer {
public:
virtual ~Observer() = default;
// 更新方法(推模型:由主题推送数据)
virtual void update(float temp, float humidity) = 0;
// 更新方法(拉模型:观察者主动获取数据)
// virtual void update(const WeatherStation& subject) = 0;
};
// 抽象主题 --------------------------------------------------
class Subject {
public:
virtual ~Subject() = default;
virtual void registerObserver(std::shared_ptr<Observer> o) = 0;
virtual void removeObserver(std::shared_ptr<Observer> o) = 0;
virtual void notifyObservers() = 0;
};
// 具体主题:气象站 -------------------------------------------
class WeatherStation : public Subject {
private:
std::vector<std::shared_ptr<Observer>> observers_;
float temperature_ = 0.0f;
float humidity_ = 0.0f;
public:
// 注册观察者
void registerObserver(std::shared_ptr<Observer> o) override {
observers_.push_back(o);
std::cout << "[系统] 新的观察者已注册\n";
}
// 移除观察者
void removeObserver(std::shared_ptr<Observer> o) override {
auto it = std::remove(observers_.begin(), observers_.end(), o);
if(it != observers_.end()) {
observers_.erase(it, observers_.end());
std::cout << "[系统] 观察者已移除\n";
}
}
// 通知所有观察者(推模型实现)
void notifyObservers() override {
std::cout << "[系统] 开始通知" << observers_.size() << "个观察者...\n";
for(auto& observer : observers_) {
observer->update(temperature_, humidity_);
}
}
// 业务方法:更新气象数据
void setMeasurements(float temp, float humidity) {
this->temperature_ = temp;
this->humidity_ = humidity;
std::cout << "\n=== 气象站更新数据 ===" << std::endl;
notifyObservers();
}
// 供拉模型使用的数据获取接口
float getTemperature() const { return temperature_; }
float getHumidity() const { return humidity_; }
};
// 具体观察者:手机APP ----------------------------------------
class MobileApp : public Observer {
private:
std::string userName_;
public:
explicit MobileApp(std::string name) : userName_(std::move(name)) {}
// 实现更新接口(推模型)
void update(float temp, float humidity) override {
std::cout << "[手机APP] " << userName_ << "收到更新:"
<< temp << "°C, " << humidity << "%\n";
// 可以在此添加业务逻辑,如触发界面刷新
}
};
// 具体观察者:户外大屏 ---------------------------------------
class OutdoorScreen : public Observer {
public:
void update(float temp, float humidity) override {
std::cout << "[户外大屏] 最新天气:"
<< temp << "°C | 湿度 " << humidity << "%\n";
// 实际项目可能包含图形渲染逻辑
}
};
// 客户端使用 ------------------------------------------------
int main() {
// 创建主题
WeatherStation station;
// 创建观察者(使用智能指针管理)
auto user1 = std::make_shared<MobileApp>("张三");
auto user2 = std::make_shared<MobileApp>("李四");
auto screen = std::make_shared<OutdoorScreen>();
// 注册观察者
station.registerObserver(user1);
station.registerObserver(user2);
station.registerObserver(screen);
// 模拟数据变化
station.setMeasurements(25.5, 60);
station.setMeasurements(23.0, 65);
// 移除一个观察者
station.removeObserver(user2);
// 再次更新数据
station.setMeasurements(20.0, 70);
return 0;
}
代码注释解析
-
内存管理改进
- 使用
std::shared_ptr
智能指针管理观察者对象 - 防止原始指针可能导致的野指针问题
std::vector<std::shared_ptr<Observer>> observers_;
- 使用
-
推模型 vs 拉模型
- 当前实现为推模型(直接传递数据)
- 注释部分展示了拉模型的接口设计
/* 拉模型实现示例 void update(const WeatherStation& subject) override { float temp = subject.getTemperature(); float humidity = subject.getHumidity(); // 使用获取的数据... } */
-
观察者类型多样化
- 实现不同观察者类型(
MobileApp
和OutdoorScreen
) - 展示不同观察者的差异化处理逻辑
- 实现不同观察者类型(
-
安全移除机制
- 使用
std::remove
+erase
组合安全删除元素 - 避免迭代器失效问题
auto it = std::remove(observers_.begin(), observers_.end(), o); if(it != observers_.end()) { observers_.erase(it, observers_.end()); }
- 使用
5. 模式优劣分析
优势:
- 松耦合:主题无需知道观察者的具体实现
- 动态订阅:运行时随时添加/移除观察者
- 广播通信:支持一对多通知机制
劣势:
- 更新顺序不可控:观察者接收通知的顺序不确定
- 性能损耗:大量观察者时遍历效率低(可考虑异步优化)
6. 应用场景
- GUI事件处理
- 按钮点击事件通知多个控件
- 实时监控系统
- 传感器数据变化通知多个终端
- 发布-订阅系统
- 消息中间件的核心设计模式
- 游戏开发
- 角色状态变化触发多个UI更新
7. 高级扩展方向
-
异步通知
- 使用线程池处理观察者更新
// 伪代码示例 void asyncNotify() { std::vector<std::future<void>> futures; for(auto& observer : observers_) { futures.push_back(std::async([&]{ observer->update(...); })); } }
-
事件过滤
- 添加事件类型参数,实现选择性通知
enum class EventType { TEMP_CHANGE, HUMIDITY_CHANGE }; virtual void update(EventType type, float value);
-
优先级队列
- 使用优先队列管理观察者
std::priority_queue<std::shared_ptr<Observer>> pq_;
8. 总结
观察者模式通过建立高效的发布-订阅机制,有效降低了系统组件间的耦合度。在实际应用中需要根据具体需求选择推/拉模型,并注意内存管理和线程安全等问题。