C++观察者模式
·
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象间的一对多依赖关系,当一个对象(主题)的状态发生改变时,所有依赖它的对象(观察者)都会收到通知并自动更新。这种模式也被称为"发布-订阅"模式。
观察者模式的核心角色
- 主题(Subject):被观察的对象,维护一组观察者,提供添加、删除观察者和通知观察者的接口
- 观察者(Observer):定义接收通知的接口,当主题状态变化时得到通知并更新
- 具体主题(Concrete Subject):实现主题接口,维护状态,状态变化时通知所有观察者
- 具体观察者(Concrete Observer):实现观察者接口,定义收到通知后的具体行为
观察者模式的实现示例
下面以"气象站系统"为例展示观察者模式的实现,气象站(主题)会定期更新天气数据,多个显示设备(观察者)会实时显示最新的天气信息:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// 前向声明
class Subject;
// 观察者接口
class Observer {
public:
virtual void update(float temperature, float humidity, float pressure) = 0;
virtual ~Observer() = default;
};
// 主题接口
class Subject {
public:
virtual void registerObserver(Observer* observer) = 0;
virtual void removeObserver(Observer* observer) = 0;
virtual void notifyObservers() = 0;
virtual ~Subject() = default;
};
// 具体主题:气象数据
class WeatherData : public Subject {
private:
std::vector<Observer*> observers; // 观察者列表
float temperature; // 温度
float humidity; // 湿度
float pressure; // 气压
public:
void registerObserver(Observer* observer) override {
observers.push_back(observer);
}
void removeObserver(Observer* observer) override {
for (auto it = observers.begin(); it != observers.end(); ++it) {
if (*it == observer) {
observers.erase(it);
break;
}
}
}
void notifyObservers() override {
// 通知所有观察者
for (Observer* observer : observers) {
observer->update(temperature, humidity, pressure);
}
}
// 当气象数据更新时调用
void measurementsChanged() {
notifyObservers();
}
// 设置气象数据
void setMeasurements(float temp, float humi, float press) {
temperature = temp;
humidity = humi;
pressure = press;
measurementsChanged(); // 数据变化,通知观察者
}
};
// 具体观察者:当前天气显示器
class CurrentConditionsDisplay : public Observer {
private:
float temperature;
float humidity;
Subject* weatherData; // 保存主题引用,便于后续取消订阅
public:
CurrentConditionsDisplay(Subject* subject) : weatherData(subject) {
// 注册为观察者
weatherData->registerObserver(this);
}
~CurrentConditionsDisplay() override {
// 取消注册
weatherData->removeObserver(this);
}
void update(float temp, float humi, float press) override {
temperature = temp;
humidity = humi;
display();
}
void display() const {
std::cout << "当前天气状况: " << temperature
<< "°C, 湿度 " << humidity << "%" << std::endl;
}
};
// 具体观察者:统计信息显示器
class StatisticsDisplay : public Observer {
private:
float maxTemp;
float minTemp;
float avgTemp;
int count;
Subject* weatherData;
public:
StatisticsDisplay(Subject* subject) : weatherData(subject) {
maxTemp = -1000;
minTemp = 1000;
avgTemp = 0;
count = 0;
weatherData->registerObserver(this);
}
~StatisticsDisplay() override {
weatherData->removeObserver(this);
}
void update(float temp, float humi, float press) override {
maxTemp = std::max(maxTemp, temp);
minTemp = std::min(minTemp, temp);
avgTemp = (avgTemp * count + temp) / (count + 1);
count++;
display();
}
void display() const {
std::cout << "温度统计: 平均 " << avgTemp
<< "°C, 最高 " << maxTemp
<< "°C, 最低 " << minTemp << "°C" << std::endl;
}
};
// 客户端使用
int main() {
// 创建主题:气象数据
WeatherData* weatherData = new WeatherData();
// 创建观察者:各种显示器
Observer* currentDisplay = new CurrentConditionsDisplay(weatherData);
Observer* statsDisplay = new StatisticsDisplay(weatherData);
// 模拟气象数据更新
std::cout << "=== 第一次更新 ===" << std::endl;
weatherData->setMeasurements(25.5f, 65.0f, 1013.0f);
std::cout << "\n=== 第二次更新 ===" << std::endl;
weatherData->setMeasurements(26.3f, 63.0f, 1012.5f);
std::cout << "\n=== 第三次更新 ===" << std::endl;
weatherData->setMeasurements(24.8f, 68.0f, 1013.5f);
// 清理资源
delete statsDisplay;
delete currentDisplay;
delete weatherData;
return 0;
}
观察者模式的工作流程
- 观察者通过主题的
registerObserver()方法注册自己 - 当主题状态发生变化时,调用
notifyObservers()方法 - 主题遍历所有注册的观察者,调用它们的
update()方法传递新状态 - 观察者收到通知后,根据新状态更新自己
- 观察者可以通过
removeObserver()方法取消订阅
推模型与拉模型
观察者模式有两种数据传递方式:
- 推模型:主题主动将详细数据推送给观察者(如示例所示)
- 拉模型:主题只通知有变化,观察者主动从主题拉取所需数据
推模型更直接,拉模型更灵活,观察者可以按需获取数据。
观察者模式的应用场景
- 事件处理系统(如GUI中的按钮点击事件)
- 发布-订阅系统(如消息队列、通知系统)
- 监控系统(如性能监控、状态监控)
- 数据同步场景(如多个视图展示同一份数据)
观察者模式的优缺点
优点:
- 实现了主题和观察者的解耦,它们可以独立变化
- 支持广播通信,主题的状态变化可以通知所有观察者
- 符合开放-封闭原则,新增观察者无需修改主题代码
- 可以动态添加或移除观察者,灵活性高
缺点:
- 如果存在大量观察者,通知可能需要较多时间
- 观察者之间没有优先级,无法保证通知顺序
- 可能导致循环依赖,引发系统崩溃
- 观察者可能会收到不需要的通知,浪费资源
观察者模式在C++的许多库和框架中都有应用,例如Qt的信号与槽机制就是观察者模式的一种实现,MFC中的消息映射机制也采用了类似思想。在现代应用开发中,观察者模式是构建松耦合系统的重要工具。
更多推荐

所有评论(0)