文章目录
观察者模式(Observer Pattern)是一种 行为型设计模式,用于建立对象间的一对多依赖关系。当一个对象(被观察者)状态变化时,所有依赖它的对象(观察者)都会自动收到通知并更新。
核心概念
- Subject(主题):维护观察者列表,提供注册、注销和通知观察者的接口。
- Observer(观察者):定义更新接口,供主题状态变化时调用。
- ConcreteSubject(具体主题):实现主题接口,存储具体状态,状态变化时通知观察者。
- ConcreteObserver(具体观察者):实现观察者接口,保存对具体主题的引用,同步自身状态。
C++ 实现示例:气象站数据监测
假设一个气象站(WeatherData
)实时更新温度、湿度、气压,多个显示屏(如当前天气、统计数据)需要动态显示最新数据。
1. 定义观察者接口
#include <iostream>
#include <list>
#include <algorithm>
// 观察者接口
class Observer {
public:
virtual ~Observer() = default;
virtual void update(class Subject* subject) = 0;
};
2. 定义主题基类
class Subject {
public:
virtual ~Subject() = default;
void attach(Observer* observer) { observers_.push_back(observer); }
void detach(Observer* observer) { observers_.remove(observer); }
void notify() {
for (auto observer : observers_) {
observer->update(this);
}
}
private:
std::list<Observer*> observers_; // 观察者列表(使用原始指针)
};
3. 实现具体主题:气象数据
class WeatherData : public Subject {
public:
void setMeasurements(float temp, float humidity, float pressure) {
temp_ = temp;
humidity_ = humidity;
pressure_ = pressure;
notify(); // 数据更新后通知观察者
}
float getTemperature() const { return temp_; }
float getHumidity() const { return humidity_; }
float getPressure() const { return pressure_; }
private:
float temp_ = 0.0f;
float humidity_ = 0.0f;
float pressure_ = 0.0f;
};
4. 实现具体观察者:当前天气显示
class CurrentConditionsDisplay : public Observer {
public:
explicit CurrentConditionsDisplay(WeatherData* weatherData) : weatherData_(weatherData) {
weatherData_->attach(this); // 注册到主题
}
~CurrentConditionsDisplay() {
if (weatherData_) weatherData_->detach(this); // 注销观察者
}
void update(Subject* subject) override {
WeatherData* wd = dynamic_cast<WeatherData*>(subject);
if (wd) {
temp_ = wd->getTemperature();
humidity_ = wd->getHumidity();
display();
}
}
void display() const {
std::cout << "Current Conditions: " << temp_ << "°C, "
<< humidity_ << "% humidity\n";
}
private:
WeatherData* weatherData_;
float temp_ = 0.0f;
float humidity_ = 0.0f;
};
5. 使用示例
int main() {
WeatherData weatherData;
CurrentConditionsDisplay currentDisplay(&weatherData);
// 更新气象数据,自动触发通知
weatherData.setMeasurements(25.5, 65, 1013.1);
weatherData.setMeasurements(26.8, 70, 1012.5);
return 0;
}
关键点解析
- 松耦合:观察者无需知道主题的具体实现,只需依赖抽象接口。
- 动态注册:可运行时添加/删除观察者。
- 通知机制:主题通过调用
notify()
遍历所有观察者并触发更新。
改进与注意事项
-
内存安全:
- 问题:原始指针可能导致悬挂指针(如观察者销毁后未注销)。
- 改进:使用
std::shared_ptr
和std::weak_ptr
管理生命周期。
class Subject { private: std::list<std::weak_ptr<Observer>> observers_; };
-
线程安全:
- 在
attach
/detach
/notify
中加锁(如std::mutex
)确保多线程安全。
- 在
-
避免循环依赖:
- 观察者持有主题的
shared_ptr
时,需用weak_ptr
打破循环引用。
- 观察者持有主题的
完整代码改进版(使用智能指针)
#include <memory>
#include <mutex>
class Observer : public std::enable_shared_from_this<Observer> {
public:
virtual ~Observer() = default;
virtual void update(Subject* subject) = 0;
};
class Subject {
public:
void attach(std::shared_ptr<Observer> observer) {
std::lock_guard<std::mutex> lock(mutex_);
observers_.emplace_back(observer);
}
void detach(std::shared_ptr<Observer> observer) {
std::lock_guard<std::mutex> lock(mutex_);
observers_.remove_if([&](auto& wp) {
auto sp = wp.lock();
return sp && sp == observer;
});
}
void notify() {
std::lock_guard<std::mutex> lock(mutex_);
for (auto& wp : observers_) {
if (auto sp = wp.lock()) {
sp->update(this);
}
}
}
private:
std::list<std::weak_ptr<Observer>> observers_;
std::mutex mutex_;
};
总结
观察者模式通过解耦主题和观察者,实现了灵活的事件通知机制。在C++中需特别注意内存管理和线程安全,合理使用智能指针和同步机制可显著提升代码健壮性。