设计模式三:观察者模式 (Observer Pattern)

观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象(称为"主题"或"可观察对象")的状态发生改变时,所有依赖它的对象(称为"观察者")都会自动收到通知并更新。

主要组成部分

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结构图

优点

  1. 松耦合:主题和观察者之间是松耦合的,主题不需要知道观察者的具体类。

  2. 动态关系:可以在运行时动态添加或删除观察者。

  3. 广播通信:主题可以一次通知多个观察者。

缺点

  1. 意外更新:由于观察者不知道其他观察者的存在,可能导致意外的更新。

  2. 性能问题:如果有大量观察者,通知所有观察者可能会花费较长时间。

应用场景

  1. 当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要改变时。

  2. 当一个对象需要通知其他对象,但又不希望与这些对象形成紧耦合时。

  3. GUI事件处理、发布-订阅系统、MVC架构等。

变体

  1. 推模型:主题将详细的变化数据推送给观察者(如上面的示例)。

  2. 拉模型:主题只通知观察者状态已改变,观察者根据需要从主题拉取数据。

观察者模式是许多软件系统中事件处理的基础,理解它对于设计灵活、可扩展的系统非常重要。