【设计模式】行为型模式-观察者模式(Observer Pattern)


观察者模式(Observer Pattern)是一种 行为型设计模式,用于建立对象间的一对多依赖关系。当一个对象(被观察者)状态变化时,所有依赖它的对象(观察者)都会自动收到通知并更新。

核心概念

  1. Subject(主题):维护观察者列表,提供注册、注销和通知观察者的接口。
  2. Observer(观察者):定义更新接口,供主题状态变化时调用。
  3. ConcreteSubject(具体主题):实现主题接口,存储具体状态,状态变化时通知观察者。
  4. 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;
}

关键点解析

  1. 松耦合:观察者无需知道主题的具体实现,只需依赖抽象接口。
  2. 动态注册:可运行时添加/删除观察者。
  3. 通知机制:主题通过调用notify()遍历所有观察者并触发更新。

改进与注意事项

  1. 内存安全

    • 问题:原始指针可能导致悬挂指针(如观察者销毁后未注销)。
    • 改进:使用std::shared_ptrstd::weak_ptr管理生命周期。
    class Subject {
    private:
        std::list<std::weak_ptr<Observer>> observers_;
    };
    
  2. 线程安全

    • attach/detach/notify中加锁(如std::mutex)确保多线程安全。
  3. 避免循环依赖

    • 观察者持有主题的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++中需特别注意内存管理和线程安全,合理使用智能指针和同步机制可显著提升代码健壮性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晴雨日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值