观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象(称为"主题"或"可观察对象")的状态发生改变时,所有依赖它的对象(称为"观察者")都会自动收到通知并更新。
主要组成部分
Subject (主题/可观察对象)
-
维护一个观察者列表
-
提供添加和删除观察者的方法
-
提供通知观察者的方法
Observer (观察者)
- 定义一个更新接口,用于在主题状态改变时接收通知
ConcreteSubject (具体主题)
-
存储对观察者有意义的状态
-
当状态改变时,向观察者发送通知
ConcreteObserver (具体观察者)
-
维护一个对具体主题对象的引用
-
实现观察者更新接口,使自身状态与主题状态保持一致
代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
// 前向声明
class Observer;
// 主题接口
class Subject {
public:
virtual ~Subject() = default;
virtual void registerObserver(Observer* o) = 0;
virtual void removeObserver(Observer* o) = 0;
virtual void notifyObservers() = 0;
};
// 观察者接口
class Observer {
public:
virtual ~Observer() = default;
virtual void update(float temp, float humidity, float pressure) = 0;
};
// 具体主题 - 气象数据
class WeatherData : public Subject {
public:
void registerObserver(Observer* o) override {
observers.push_back(o);
}
void removeObserver(Observer* o) override {
observers.erase(
std::remove(observers.begin(), observers.end(), o),
observers.end()
);
}
void notifyObservers() override {
for (auto* observer : observers) {
observer->update(temperature, humidity, pressure);
}
}
void measurementsChanged() {
notifyObservers();
}
void setMeasurements(float temp, float humidity, float pressure) {
this->temperature = temp;
this->humidity = humidity;
this->pressure = pressure;
measurementsChanged();
}
private:
std::vector<Observer*> observers;
float temperature = 0.0f;
float humidity = 0.0f;
float pressure = 0.0f;
};
// 具体观察者 - 当前状况显示
class CurrentConditionsDisplay : public Observer {
public:
explicit CurrentConditionsDisplay(Subject* weatherData)
: weatherData(weatherData) {
weatherData->registerObserver(this);
}
~CurrentConditionsDisplay() {
weatherData->removeObserver(this);
}
void update(float temp, float humidity, float pressure) override {
this->temperature = temp;
this->humidity = humidity;
display();
}
void display() const {
std::cout << "Current conditions: " << temperature
<< "°C and " << humidity << "% humidity\n";
}
private:
Subject* weatherData;
float temperature = 0.0f;
float humidity = 0.0f;
};
// 使用示例
int main() {
WeatherData weatherData;
CurrentConditionsDisplay currentDisplay(&weatherData);
weatherData.setMeasurements(25, 65, 1013);
weatherData.setMeasurements(26, 70, 1012);
return 0;
}
uml结构图
优点
-
松耦合:主题和观察者之间是松耦合的,主题不需要知道观察者的具体类。
-
动态关系:可以在运行时动态添加或删除观察者。
-
广播通信:主题可以一次通知多个观察者。
缺点
-
意外更新:由于观察者不知道其他观察者的存在,可能导致意外的更新。
-
性能问题:如果有大量观察者,通知所有观察者可能会花费较长时间。
应用场景
-
当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要改变时。
-
当一个对象需要通知其他对象,但又不希望与这些对象形成紧耦合时。
-
GUI事件处理、发布-订阅系统、MVC架构等。
变体
-
推模型:主题将详细的变化数据推送给观察者(如上面的示例)。
-
拉模型:主题只通知观察者状态已改变,观察者根据需要从主题拉取数据。
观察者模式是许多软件系统中事件处理的基础,理解它对于设计灵活、可扩展的系统非常重要。