Bootstrap

「软件设计模式」观察者模式(Observer)

深入解析观察者模式:构建灵活的对象通知机制

一、模式思想与核心价值

观察者模式(Observer)是一种行为型设计模式,它建立了对象间的一对多依赖关系。当被观察对象(Subject)状态发生变化时,它会自动通知所有观察者(Observer)对象,形成松耦合的交互机制。这种模式的核心价值体现在:

  1. 解耦原则:分离观察者与被观察者的具体实现
  2. 动态订阅:支持运行时添加/移除观察者
  3. 事件驱动:建立高效的状态变更通知机制
  4. 广播通信:实现一对多的消息传递模式

二、模式结构与组件分析

核心角色:

  1. Subject(目标)

    • 维护观察者列表
    • 提供订阅/取消订阅接口
    • 通知观察者的方法
  2. Observer(观察者)

    • 定义更新接口
    • 接收Subject状态变更通知
  3. ConcreteSubject(具体目标)

    • 存储具体状态信息
    • 状态改变时触发通知
  4. ConcreteObserver(具体观察者)

    • 实现更新逻辑
    • 维护与Subject的引用

三、C++实现示例:气象监测系统

传统实现版本

#include <algorithm>
#include <iostream>
#include <vector>

// 前置声明
class Observer;

// Subject接口
class WeatherData {
public:
    virtual void registerObserver(Observer* o) = 0;
    virtual void removeObserver(Observer* o) = 0;
    virtual void notifyObservers() = 0;
    virtual ~WeatherData() = default;
};

// Observer接口
class Observer {
public:
    virtual void update(float temp, float humidity, float pressure) = 0;
    virtual ~Observer() = default;
};

// 具体Subject实现
class ConcreteWeatherData : public WeatherData {
private:
    std::vector<Observer*> observers;
    float temperature;
    float humidity;
    float pressure;

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& obs : observers) {
            obs->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();
    }
};

// 具体Observer实现
class CurrentConditionsDisplay : public Observer {
private:
    float temperature;
    float humidity;
    WeatherData* weatherData;

public:
    explicit CurrentConditionsDisplay(WeatherData* wd) : weatherData(wd) {
        weatherData->registerObserver(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
                     ";
    }

    ~CurrentConditionsDisplay() {
        weatherData->removeObserver(this);
    }
};

// 使用示例
int main() {
    ConcreteWeatherData weatherData;
    CurrentConditionsDisplay currentDisplay(&weatherData);

    weatherData.setMeasurements(25.5, 65, 1013.2);
    weatherData.setMeasurements(26.8, 70, 1012.8);

    return 0;
}

运行结果

Current conditions: 25.5°C and 65% humidity
Current conditions: 26.8°C and 70% humidity

现代C++改进版本(使用智能指针)

#include <algorithm>
#include <memory>
#include <vector>

class Observer;

class WeatherData {
public:
    virtual void registerObserver(std::shared_ptr<Observer> o) = 0;
    virtual void removeObserver(std::shared_ptr<Observer> o) = 0;
    virtual void notifyObservers() = 0;
    virtual ~WeatherData() = default;
};

class Observer : public std::enable_shared_from_this<Observer> {
public:
    virtual void update(float temp, float humidity, float pressure) = 0;
    virtual ~Observer() = default;
};

class ConcreteWeatherData : public WeatherData {
private:
    std::vector<std::shared_ptr<Observer>> observers;
    // ...其他成员相同
    float temperature;
    float humidity;
    float pressure;

public:
    void registerObserver(std::shared_ptr<Observer> o) override {
        observers.push_back(o);
    }

    void removeObserver(std::shared_ptr<Observer> o) override {
        observers.erase(std::remove(observers.begin(), observers.end(), o), observers.end());
    }
    // ...其他实现相同

    void notifyObservers() override {
        for (auto& obs : observers) {
            obs->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();
    }
};

class CurrentConditionsDisplay : public Observer {
private:
    std::weak_ptr<WeatherData> weatherData;
    float temperature;
    float humidity;
    // ...其他成员相同

public:
    explicit CurrentConditionsDisplay(std::shared_ptr<WeatherData> wd) : weatherData(wd) {}
    /**
     * CurrentConditionsDisplay 对象时,shared_from_this() 被调用,而此时 shared_ptr
     * 尚未完全构建。为了避免这个问题,可以在构造函数中使用 std::enable_shared_from_this 的 shared_from_this()
     * 方法之前确保对象已经被 shared_ptr 管理。
     */
    void init() {
        if (auto w = weatherData.lock()) {
            w->registerObserver(shared_from_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" << std::endl;
    }

    ~CurrentConditionsDisplay() {
        if (auto w = weatherData.lock()) {
            w->removeObserver(shared_from_this());
        }
    }
};

main.cc:

#include <iostream>
#include <memory>
#include "modern_observer.h"

int main() {
    // 创建 WeatherData 对象
    std::shared_ptr<ConcreteWeatherData> weatherData = std::make_shared<ConcreteWeatherData>();

    // 创建观察者
    auto currentDisplay = std::make_shared<CurrentConditionsDisplay>(weatherData);
    currentDisplay->init();
    // 模拟新的天气数据
    weatherData->setMeasurements(25.0f, 65.0f, 1013.0f);
    weatherData->setMeasurements(27.0f, 70.0f, 1012.0f);
    weatherData->setMeasurements(23.0f, 90.0f, 1011.0f);

    return 0;
}

 运行结果:

Current conditions: 25°C and 65% humidity
Current conditions: 27°C and 70% humidity
Current conditions: 23°C and 90% humidity

四、应用场景与最佳实践

典型应用场景

  1. GUI事件处理系统
  2. 股票价格变动通知
  3. 游戏引擎中的成就系统
  4. 分布式系统的状态同步
  5. 实时数据监控平台

实现注意事项

  1. 线程安全:多线程环境下的同步控制
  2. 通知策略:推模式 vs 拉模式
  3. 生命周期管理:防止悬空指针/引用
  4. 性能优化:批量通知与异步处理
  5. 循环依赖:避免观察链形成闭环

五、模式优劣分析

优势:

  • 符合开闭原则:易于新增观察者
  • 运行时动态建立对象关系
  • 抽象耦合降低系统依赖性
  • 支持广播通信机制

局限:

  • 通知顺序不可控
  • 过度使用可能导致性能问题
  • 需要维护观察者列表
  • 调试复杂度增加

六、扩展与变体

  1. 事件总线模式:集中式的事件管理
  2. 反应式编程:基于数据流的观察者模式
  3. 委托机制:C#等语言的委托实现
  4. 发布-订阅模式:解耦程度更高的变体

通过本文的详细讲解和代码示例,读者可以深入理解观察者模式的核心思想,掌握其在C++中的实现方法。该模式在需要建立对象间动态、松耦合关系的场景中具有重要价值,合理运用可以显著提升系统的灵活性和可维护性。后续文章我们将继续探讨其他设计模式的实现与应用。

;