文章目录
- 一、观察者模式概述
- 二、传统代码 vs 观察者模式对比
- 1. 传统实现(紧耦合)
- 2. 观察者模式实现(松耦合)
- 三、Mermaid 类图说明
- 四、核心设计要点
- 1. 接口分层设计
- 2. 通知机制实现
- 3. 扩展性验证
- 五、应用场景与注意事项
- 适用场景
- 注意事项
- 1. 内存管理:需注意观察者生命周期管理,避免野指针
- 2. 通知顺序:观察者列表顺序可能影响业务逻辑
- 3. 线程安全:多线程环境下需考虑同步机制
- 4. 异常处理:单个观察者异常不应影响整体通知流程
- 六、现代C++改进方案
- 七、总结
一、观察者模式概述
观察者模式(Observer Pattern)是一种行为型设计模式,用于建立对象间的一对多依赖关系。当一个对象(被观察者)状态发生变化时,所有依赖它的对象(观察者)都会自动收到通知并更新。这种模式通过解耦通知方与接收方,实现了系统的灵活性和可扩展性。
二、传统代码 vs 观察者模式对比
1. 传统实现(紧耦合)
// 抽象显示元素接口,强制子类实现 display 方法
class DisplayElement {
public:virtual void display() = 0;
};// 具体显示类:直接绑定 WeatherData 数据
class CurrentConditionsDisplay : public DisplayElement {
public:// 接收 WeatherData 的更新数据并刷新显示void update(float temp, float humidity, float pressure) {this->temp = temp;this->humidity = humidity;this->pressure = pressure;display(); // 调用 display 展示最新数据}void display() override {std::cout << "Current conditions: " << temp << "F degrees and " << humidity << "% humidity" << std::endl;}private:float temp, humidity, pressure;
};// 被观察者类:直接持有显示对象(紧耦合)
class WeatherData {
public:// 设置天气数据并直接触发显示更新void setMeasurements(float temp, float humidity, float pressure) {this->temp = temp;this->humidity = humidity;this->pressure = pressure;// ❗️直接调用具体观察者方法,形成硬编码依赖currentDisplay.update(temp, humidity, pressure);}private:CurrentConditionsDisplay currentDisplay; // ❗️硬编码依赖具体观察者float temp, humidity, pressure;
};
问题分析:
- 紧耦合问题:
WeatherData
需要直接包含具体观察者类(如CurrentConditionsDisplay
) - 扩展困难:添加新观察者需要修改
WeatherData
类 - 违反开闭原则:系统难以对扩展开放,对修改关闭
2. 观察者模式实现(松耦合)
// 抽象观察者接口:定义统一的更新协议
class IObserver {
public:// 纯虚函数:子类必须实现 update 方法virtual void update(float temp, float humidity, float pressure) = 0;virtual ~IObserver() = default; // 虚析构确保多态释放
};// 抽象被观察者接口:定义观察者管理操作
class ISubject {
public:// 注册观察者virtual void registerObserver(IObserver* observer) = 0;// 移除观察者virtual void removeObserver(IObserver* observer) = 0;// 通知所有观察者virtual void notifyObservers() = 0;
};// 具体被观察者实现
class WeatherData : public ISubject {
public:// 实现注册观察者方法void registerObserver(IObserver* observer) override {observers.push_back(observer); // 将观察者加入列表}// 实现移除观察者方法void removeObserver(IObserver* observer) override {// 使用 std::remove 重排容器,然后 erase 删除observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());}// 实现通知观察者方法void notifyObservers() override {for (auto& observer : observers) {observer->update(temp, humidity, pressure); // 通过接口调用更新}}// 设置天气数据并触发通知void setMeasurements(float temp, float humidity, float pressure) {this->temp = temp;this->humidity = humidity;this->pressure = pressure;measurementsChanged(); // 触发状态变化通知}private:// 状态变化时调用通知逻辑void measurementsChanged() {notifyObservers(); // 通知所有注册观察者}std::vector<IObserver*> observers; // 存储观察者指针列表float temp, humidity, pressure;
};// 具体观察者实现
class CurrentConditionsDisplay : public IObserver {
public:// 构造函数自动注册到 WeatherDataCurrentConditionsDisplay(WeatherData& weatherData) {this->weatherData.registerObserver(this); // 将自身注册为观察者}// 实现 update 方法void update(float temp, float humidity, float pressure) override {this->temp = temp;this->humidity = humidity;this->pressure = pressure;display(); // 刷新显示}void display() {std::cout << "Current conditions: " << temp << "F degrees and " << humidity << "% humidity" << std::endl;}private:float temp, humidity, pressure;WeatherData& weatherData; // 引用 WeatherData 实例
};
(一堆观察者,一堆被观察者,一堆接口;被观察者提供观察者注册、解绑、通知接口,被观察者提供数据更新并通知方法;观察者实现被观察者注册构造方法,实现更新接口,实现展示方法)
改进优势:
- 松耦合:
WeatherData
只依赖抽象接口IObserver
- 可扩展性强:新增观察者只需实现
IObserver
接口 - 符合开闭原则:无需修改
WeatherData
即可扩展功能
三、Mermaid 类图说明
四、核心设计要点
1. 接口分层设计
- ISubject 接口:定义观察者管理方法(注册/移除/通知)
- IObserver 接口:定义更新方法的标准化协议
- 具体实现类:通过组合方式实现接口协作
2. 通知机制实现
void WeatherData::notifyObservers() {for (auto& observer : observers) {observer->update(temp, humidity, pressure); // 通过接口调用具体实现}
}
- 使用迭代器遍历观察者列表
- 通过统一接口调用更新方法
- 实现"广播-订阅"通信模式
3. 扩展性验证
新增统计显示观察者只需:
class StatisticsDisplay : public IObserver {
public:void update(float temp, float humidity, float pressure) override {temps.push_back(temp);// 计算统计信息...display();}void display() {std::cout << "Stats: Max/Min/Avg temperature..." << std::endl;}
private:std::vector<float> temps;
};
无需修改 WeatherData 类即可实现功能扩展
五、应用场景与注意事项
适用场景
- GUI 事件处理系统(如按钮点击事件)
- 实时数据监控系统
- 分布式事件总线架构
- 游戏中的事件驱动系统
注意事项
1. 内存管理:需注意观察者生命周期管理,避免野指针
2. 通知顺序:观察者列表顺序可能影响业务逻辑
3. 线程安全:多线程环境下需考虑同步机制
4. 异常处理:单个观察者异常不应影响整体通知流程
六、现代C++改进方案
使用智能指针和lambda表达式增强安全性:
class ModernWeatherData : public ISubject {
public:void registerObserver(std::shared_ptr<IObserver> observer) override {observers.push_back(observer); // 使用智能指针避免内存泄漏}// ...其他方法...
private:std::vector<std::shared_ptr<IObserver>> observers; // 智能指针容器
};
七、总结
特性 | 传统实现 | 观察者模式 |
---|---|---|
对象耦合度 | 高 | 低 |
扩展性 | 需修改现有代码 | 支持开闭原则 |
维护成本 | 高 | 低 |
通知灵活性 | 固定调用 | 动态注册/注销 |
适用场景复杂度 | 简单场景 | 复杂系统架构 |
观察者模式通过接口抽象和行为封装,为复杂系统提供了优雅的通信解决方案。在C++中实现时需注意接口设计规范、内存管理和线程安全等工程实践问题,合理使用智能指针和现代C++特性可进一步提升代码质量。