跳转到内容

C++ 观察者模式

来自代码酷

观察者模式(Observer Pattern)是设计模式中一种行为型模式,用于在对象之间建立一对多的依赖关系,使得当一个对象(主题/被观察者)状态改变时,所有依赖它的对象(观察者)会自动收到通知并更新。该模式广泛应用于事件处理系统、GUI组件交互和实时数据推送等场景。

基本概念[编辑 | 编辑源代码]

观察者模式的核心角色包括:

  • Subject(主题):维护一个观察者列表,提供添加、删除和通知观察者的接口。
  • Observer(观察者):定义一个更新接口,用于接收主题状态变更的通知。
  • ConcreteSubject(具体主题):实现主题的具体逻辑,存储状态并在状态变化时通知观察者。
  • ConcreteObserver(具体观察者):实现观察者的更新逻辑,对主题状态变化做出响应。

模式结构[编辑 | 编辑源代码]

classDiagram class Subject { +attach(Observer o) +detach(Observer o) +notify() } class Observer { +update() } class ConcreteSubject { -state +getState() +setState() } class ConcreteObserver { -subject +update() } Subject <|-- ConcreteSubject Observer <|-- ConcreteObserver ConcreteSubject o-- ConcreteObserver

C++实现示例[编辑 | 编辑源代码]

以下是一个简单的C++实现,展示温度传感器(主题)与显示器(观察者)的交互:

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

// 前向声明  
class Observer;  

// 主题基类  
class Subject {  
public:  
    virtual void attach(Observer* o) = 0;  
    virtual void detach(Observer* o) = 0;  
    virtual void notify() = 0;  
};  

// 观察者基类  
class Observer {  
public:  
    virtual void update(float temperature) = 0;  
};  

// 具体主题:温度传感器  
class TemperatureSensor : public Subject {  
private:  
    std::vector<Observer*> observers;  
    float temperature;  
public:  
    void attach(Observer* o) override {  
        observers.push_back(o);  
    }  
    void detach(Observer* o) override {  
        observers.erase(std::remove(observers.begin(), observers.end(), o), observers.end());  
    }  
    void notify() override {  
        for (auto* o : observers) {  
            o->update(temperature);  
        }  
    }  
    void setTemperature(float temp) {  
        temperature = temp;  
        notify(); // 状态变化时通知观察者  
    }  
};  

// 具体观察者:温度显示器  
class TemperatureDisplay : public Observer {  
public:  
    void update(float temperature) override {  
        std::cout << "Temperature updated: " << temperature << "°C\n";  
    }  
};  

int main() {  
    TemperatureSensor sensor;  
    TemperatureDisplay display;  
    sensor.attach(&display);  

    sensor.setTemperature(23.5); // 输出:Temperature updated: 23.5°C  
    sensor.setTemperature(25.0); // 输出:Temperature updated: 25°C  

    return 0;  
}

代码解释[编辑 | 编辑源代码]

1. SubjectObserver 是抽象基类,定义接口规范。 2. TemperatureSensor 是具体主题,维护观察者列表并在温度变化时调用 `notify()`。 3. TemperatureDisplay 是具体观察者,实现 `update()` 方法以响应状态变化。 4. 在 `main()` 中,传感器与显示器通过观察者模式解耦,传感器无需直接调用显示器的接口。

实际应用场景[编辑 | 编辑源代码]

观察者模式在以下场景中非常有用:

  • GUI事件处理:如按钮点击事件通知多个监听器。
  • 发布-订阅系统:如消息队列中的生产者-消费者模型。
  • 游戏开发:角色状态变化触发UI或AI的更新。

案例:股票价格通知[编辑 | 编辑源代码]

假设有一个股票交易系统,当股票价格变化时,需要通知所有订阅该股票的投资者:

  
// 省略基类定义(与温度示例类似)  

class Stock : public Subject {  
private:  
    std::string symbol;  
    double price;  
public:  
    Stock(const std::string& s, double p) : symbol(s), price(p) {}  
    void setPrice(double p) {  
        price = p;  
        notify();  
    }  
    std::string getSymbol() const { return symbol; }  
    double getPrice() const { return price; }  
};  

class Investor : public Observer {  
private:  
    std::string name;  
public:  
    Investor(const std::string& n) : name(n) {}  
    void update(double price) override {  
        std::cout << name << " notified: Price changed to $" << price << "\n";  
    }  
};  

// 使用示例  
int main() {  
    Stock apple("AAPL", 150.0);  
    Investor alice("Alice"), bob("Bob");  
    apple.attach(&alice);  
    apple.attach(&bob);  

    apple.setPrice(155.5); // 输出两条通知  
}

进阶讨论[编辑 | 编辑源代码]

推模型 vs 拉模型[编辑 | 编辑源代码]

  • 推模型:主题将详细数据通过 `update()` 参数传递给观察者(如上述示例)。
  • 拉模型:观察者通过主题的接口主动获取数据(需在 `update()` 中调用 `getState()`)。

线程安全问题[编辑 | 编辑源代码]

在多线程环境中,需对观察者列表的修改和遍历加锁(如使用 `std::mutex`)。

总结[编辑 | 编辑源代码]

观察者模式通过解耦主题和观察者,增强了代码的灵活性和可维护性。C++中可通过继承和纯虚函数实现该模式,适用于需要动态响应用户交互或数据变化的系统。