1、观察者模式概述:
观察者模式(Observer Pattern),又称为发布-订阅模式(Publish-Subscribe Pattern),是一种行为设计模式,用于在对象之间建立一对多的依赖关系。当一个对象(被观察者或主题)的状态发生变化时,所有依赖于它的对象(观察者)都会收到通知,并自动更新。这样,被观察者无需关心观察者的具体实现,观察者也无需知道被观察者的内部结构,实现了解耦。
2、观察者模式的适用场景:
- 当一个对象的状态发生变化时,需要同时更新其他对象的状态,而且这些对象之间存在一对多的依赖关系。
- 当一个对象需要通知其他对象,但又不希望这些对象之间产生紧密的耦合关系。
3、观察者模式的优点:
- 解耦:观察者和被观察者之间的依赖关系是抽象的,它们可以独立地变化和复用。例如,一个天气数据提供者(被观察者)可以通知多个不同类型的显示组件(观察者),如当前温度、湿度等,而不需要关心它们的具体实现。
- 支持广播通信:一个被观察者可以通知多个观察者,实现广播通信。例如,当一个新闻发布平台发布新消息时,所有订阅者都会收到通知。
- 动态添加和移除观察者:观察者可以在运行时动态添加和移除,提高了系统的灵活性。
4、观察者模式的缺点:
- 通知顺序不可控:观察者的通知顺序取决于它们在被观察者的观察者列表中的顺序,这可能导致某些观察者在其他观察者之前收到通知,而这可能不是我们期望的顺序。
- 被观察者过于复杂:如果一个被观察者有很多观察者,或者观察者之间有复杂的依赖关系,那么被观察者需要维护一个庞大的观察者列表,可能导致其变得过于复杂。
- 可能导致无意识的循环引用:当观察者和被观察者之间存在循环引用时,可能导致无法正确地释放内存。在某些情况下,这可能导致内存泄漏和其他不良影响。
5、用C++实现一个观察者模式例子:
#include <iostream>
#include <vector>
#include <algorithm>
class Observer {
public:
virtual void update(float temperature, float humidity) = 0;
};
class Subject {
public:
virtual void registerObserver(Observer* observer) = 0;
virtual void removeObserver(Observer* observer) = 0;
virtual void notifyObservers() = 0;
};
class WeatherData : public Subject {
public:
void registerObserver(Observer* observer) override {
observers.push_back(observer);
}
void removeObserver(Observer* observer) override {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
void notifyObservers() override {
for (auto& observer : observers) {
observer->update(temperature, humidity);
}
}
void setMeasurements(float temp, float humidity) {
temperature = temp;
this->humidity = humidity;
notifyObservers();
}
private:
std::vector<Observer*> observers;
float temperature;
float humidity;
};
class TemperatureDisplay : public Observer {
public:
void update(float temperature, float humidity) override {
std::cout << "Temperature: " << temperature << " C" << std::endl;
}
};
class HumidityDisplay : public Observer {
public:
void update(float temperature, float humidity) override {
std::cout << "Humidity: " << humidity << "%" << std::endl;
}
};
int main() {
WeatherData weatherData;
TemperatureDisplay tempDisplay;
HumidityDisplay humidityDisplay;
weatherData.registerObserver(&tempDisplay);
weatherData.registerObserver(&humidityDisplay);
weatherData.setMeasurements(25.5, 60);
return 0;
}
在这个例子中,我们定义了一个Subject接口和一个Observer接口。WeatherData类实现了Subject接口,负责管理观察者列表并通知它们。TemperatureDisplay和HumidityDisplay类分别实现了Observer接口,它们分别显示温度和湿度数据。当天气数据发生变化时,WeatherData对象会通知所有注册的观察者。