观察者模式(Observer)在 C++ 中的实现详解(第二部分)

观察者模式的核心组件

观察者模式的核心组件包括两个主要角色:Subject(主题)和 Observer(观察者)。Subject 负责维护观察者列表,并在状态变化时通知所有注册的观察者。Observer 定义了接收通知的接口,通常包含一个 update 方法。

Subject 类的实现

Subject 类需要提供注册、注销和通知观察者的功能。以下是一个典型的 Subject 类实现:

#include <vector>
#include <algorithm>

class Observer;

class Subject {
public:
    virtual ~Subject() = default;
    void attach(Observer* observer) {
        observers_.push_back(observer);
    }
    void detach(Observer* observer) {
        observers_.erase(std::remove(observers_.begin(), observers_.end(), observer), observers_.end());
    }
    void notify();
private:
    std::vector<Observer*> observers_;
};
Observer 类的实现

Observer 类是一个抽象基类,定义了观察者的通用接口。具体观察者需要继承该类并实现 update 方法:

class Observer {
public:
    virtual ~Observer() = default;
    virtual void update() = 0;
};
具体 Subject 和 Observer 的实现

假设我们有一个气象站,作为 Subject,它会通知观察者(如显示设备)温度变化:

class WeatherStation : public Subject {
public:
    void setTemperature(float temp) {
        temperature_ = temp;
        notify();
    }
    float getTemperature() const { return temperature_; }
private:
    float temperature_;
};

class DisplayDevice : public Observer {
public:
    DisplayDevice(WeatherStation* station) : station_(station) {}
    void update() override {
        std::cout << "Temperature updated: " << station_->getTemperature() << std::endl;
    }
private:
    WeatherStation* station_;
};
使用观察者模式的示例

以下是使用上述类的示例代码:

int main() {
    WeatherStation station;
    DisplayDevice display(&station);
    station.attach(&display);
    station.setTemperature(25.5f);
    station.setTemperature(26.0f);
    return 0;
}
观察者模式的优缺点

优点

  • 松耦合:Subject 和 Observer 之间依赖最小化,可以独立变化。
  • 动态关系:可以在运行时动态添加或移除观察者。

缺点

  • 性能问题:如果观察者数量过多,通知可能成为性能瓶颈。
  • 循环依赖:不恰当的实现可能导致循环调用。
线程安全的观察者模式实现

在多线程环境中,观察者模式需要额外考虑线程安全问题。以下是一个线程安全的实现片段:

#include <mutex>

class ThreadSafeSubject : public Subject {
public:
    void attach(Observer* observer) {
        std::lock_guard<std::mutex> lock(mutex_);
        observers_.push_back(observer);
    }
    void notify() {
        std::lock_guard<std::mutex> lock(mutex_);
        for (auto observer : observers_) {
            observer->update();
        }
    }
private:
    std::mutex mutex_;
};
观察者模式与发布-订阅模式的区别

尽管观察者模式和发布-订阅模式类似,但两者存在关键区别:

  • 观察者模式中,Subject 直接持有 Observer 的引用并直接调用其方法。
  • 发布-订阅模式通常通过消息队列或事件总线间接通信,解耦更彻底。
实际应用场景

观察者模式广泛应用于以下场景:

  • GUI 事件处理(如按钮点击通知)。
  • 实时数据监控(如股票价格更新)。
  • 游戏开发(如角色状态变化通知)。

通过合理使用观察者模式,可以显著提升代码的可维护性和扩展性。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐