(7)观察者模式

观察者模式(Observer Pattern) 是一种行为型设计模式,它定义了对象之间 “一对多” 的依赖关系,使得当一个对象(称为 主题 / 被观察者)的状态发生变化时,所有依赖于它的对象(称为 观察者)都会自动收到通知并进行更新。
实现原理
1. 抽象基类 + 多态
 - 使用纯虚函数定义接口(Subject 和 Observer),实现松耦合。
 - 具体类通过继承实现多态调用。

2.指针或智能指针管理观察者
 - 常用 std::vector<Observer*> 存储观察者。
 - 推荐使用 std::weak_ptr 或手动管理生命周期,避免悬空指针或内存泄漏。

3. 动态注册/注销
 - 观察者可在运行时动态添加或移除,系统灵活可扩展。

4. 广播机制
 - 主题变更时,自动遍历通知所有注册的观察者。
被观察者
// ==================== 主题接口(被观察者)====================
class Subject {
public:
    virtual ~Subject() = default;
    virtual void attach(Observer* o) = 0;
    virtual void detach(Observer* o) = 0;
    virtual void notify() = 0;
};

// ==================== 具体主题:温度传感器 ====================
class TemperatureSensor : public Subject {
private:
    std::vector<Observer*> observers;
    float temperature;

public:
    // 注册观察者
    void attach(Observer* o) override {
        observers.push_back(o);
        std::cout << "观察者已注册\n";
    }

    // 移除观察者
    void detach(Observer* o) override {
        auto it = std::find(observers.begin(), observers.end(), o);
        if (it != observers.end()) {
            observers.erase(it);
            std::cout << "观察者已移除\n";
        }
    }

    // 通知所有观察者
    void notify() override {
        for (auto* obs : observers) {
            obs->update();
        }
    }

    // 设置温度(触发通知)
    void setTemperature(float temp) {
        this->temperature = temp;
        std::cout << "🌡️ 传感器更新温度:%.1f°C\n", temp;
        notify();  // 通知所有观察者
    }

    // 获取当前温度(供观察者查询)
    float getTemperature() const {
        return temperature;
    }
};
观察者
// ==================== 观察者接口 ====================
class Observer {
public:
    virtual ~Observer() = default;
    virtual void update() = 0;
};

// ==================== 具体观察者1:控制台显示器 ====================
class ConsoleDisplay : public Observer {
    TemperatureSensor* sensor;  // 持有对主题的引用

public:
    ConsoleDisplay(TemperatureSensor* s) : sensor(s) {}

    void update() override {
        float temp = sensor->getTemperature();
        std::cout << "控制台显示:当前温度为 %.1f°C\n", temp;
    }
};

// ==================== 具体观察者2:日志记录器 ====================
class Logger : public Observer {
    TemperatureSensor* sensor;

public:
    Logger(TemperatureSensor* s) : sensor(s) {}

    void update() override {
        float temp = sensor->getTemperature();
        std::cout << "日志记录:温度数据更新为 %.1f°C\n", temp;
    }
};
// ==================== 主函数测试 ====================
int main() {
    // 创建主题
    TemperatureSensor sensor;

    // 创建观察者(传入主题引用)
    ConsoleDisplay console(&sensor);
    Logger logger(&sensor);

    // 注册观察者
    sensor.attach(&console);
    sensor.attach(&logger);

    std::cout << "\n--- 第一次更新 ---\n";
    sensor.setTemperature(23.5f);

    std::cout << "\n--- 第二次更新 ---\n";
    sensor.setTemperature(26.0f);

    // 移除日志观察者
    std::cout << "\n--- 移除日志记录器 ---\n";
    sensor.detach(&logger);

    std::cout << "\n--- 第三次更新(仅控制台显示)---\n";
    sensor.setTemperature(28.2f);

    return 0;
}
进阶-使用模板,去除继承与虚函数
#include <iostream>
#include <vector>
#include <functional>

// 简单的观察者主题模板
template<typename T>
class Subject {
public:
    using Observer = std::function<void(const T&)>;

    // 注册一个观察者
    void attach(Observer obs) {
        observers.push_back(obs);
    }

    // 通知所有观察者
    void notify(const T& data) {
        for (auto& obs : observers) {
            obs(data);
        }
    }

private:
    std::vector<Observer> observers;
};

// 测试用的数据
struct Weather {
    float temperature;
    Weather(float t) : temperature(t) {}
};
int main() {
    Subject<Weather> weatherStation;

    // 观察者1注册lambda:打印温度
    weatherStation.attach([](const Weather& w) {
        std::cout << "手机显示: " << w.temperature << "°C\n";
    });

    // 观察者2注册lambda:高温提醒
    weatherStation.attach([](const Weather& w) {
        if (w.temperature > 30) {
            std::cout << "太热了!当前温度: " << w.temperature << "°C\n";
        }
    });

    // 模拟温度更新
    weatherStation.notify(Weather(25));  // 正常
    weatherStation.notify(Weather(32));  // 高温

    return 0;
}
posted @ 2018-12-12 22:21  osbreak  阅读(142)  评论(0)    收藏  举报