设计模式-observer模式(观察者模式)

发布于:2025-02-24 ⋅ 阅读:(11) ⋅ 点赞:(0)

解释

观察者模式用于建立对象间的一对多依赖,当主题(Subject)状态变化时,所有观察者(Observers)自动收到通知。
Observer 模式应该可以说是应用最多、影响最广的模式之一,因为 Observer 的一个实例 Model/View/Control(MVC)结构在系统开发架构设计中有着很重要的地位和意义。

典型应用场景

  1. GUI事件响应(如按钮点击触发多个控件更新)
  2. 数据实时同步(如股票价格变动通知多个客户端)
  3. 游戏引擎中的事件系统(如角色死亡触发任务失败/成就解锁)

不使用观察者模式的缺点

假设要实现一个天气监测系统,当温度变化时通知手机App和LED屏幕。若直接硬编码调用所有依赖对象,会导致以下问题:

  1. 高耦合主题类(WeatherStation)直接依赖具体观察者类,违反依赖倒置原则。
  2. 扩展困难新增观察者类型(如Web界面)需修改主题类代码,违反开闭原则。
  3. 代码冗余需要手动管理所有观察者的调用逻辑。

代码对比

1. 不使用观察者模式(硬编码调用)

#include <iostream>

// 具体显示设备类(紧耦合)
class MobileApp {
public:
    void update(float temp) {
        std::cout << "Mobile App: Temperature updated to " << temp << "°C\n";
    }
};

class LEDScreen {
public:
    void refresh(float temp) {
        std::cout << "LED Screen: New temperature = " << temp << "°C\n";
    }
};

// 主题类(直接管理所有设备)
class WeatherStation {
    MobileApp* mobileApp;  // 直接依赖具体类
    LEDScreen* ledScreen;  // 新增设备需添加成员变量
    float temperature;

public:
    WeatherStation(MobileApp* app, LEDScreen* screen) 
        : mobileApp(app), ledScreen(screen) {}

    void setTemperature(float temp) {
        temperature = temp;
        // 必须显式调用所有设备的方法
        mobileApp->update(temp);
        ledScreen->refresh(temp);
    }
};

int main() {
    MobileApp app;
    LEDScreen screen;
    WeatherStation station(&app, &screen);
    station.setTemperature(25.5);
}

缺点分析:

  • 添加新设备(如WebInterface)需修改WeatherStation的构造函数和setTemperature方法。
  • 主题类与具体观察者类紧密耦合,单元测试困难。
  • 无法动态增减观察者(如运行时移除LED屏幕)。

2. 使用观察者模式优化

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

// 抽象观察者接口(解耦核心)
class Observer {
public:
    virtual void update(float temp) = 0;
    virtual ~Observer() = default;
};

// 具体观察者实现
class MobileApp : public Observer {
public:
    void update(float temp) override {
        std::cout << "Mobile App: Temperature updated to " << temp << "°C\n";
    }
};

class LEDScreen : public Observer {
public:
    void update(float temp) override {
        std::cout << "LED Screen: New temperature = " << temp << "°C\n";
    }
};

// 主题类(面向接口编程)
class WeatherStation {
    std::vector<Observer*> observers;  // 统一管理抽象接口
    float temperature;

public:
    void addObserver(Observer* obs) { observers.push_back(obs); }
    void removeObserver(Observer* obs) {
        observers.erase(std::remove(observers.begin(), observers.end(), obs), observers.end());
    }

    void setTemperature(float temp) {
        temperature = temp;
        for (auto obs : observers) {
            obs->update(temp);  // 统一调用接口
        }
    }
};

int main() {
    WeatherStation station;
    MobileApp app;
    LEDScreen screen;

    station.addObserver(&app);
    station.addObserver(&screen);
    station.setTemperature(25.5);  // 输出两者的通知

    // 动态移除观察者
    station.removeObserver(&screen);
    station.setTemperature(26.0);  // 仅输出Mobile App
}

优点:

  • 主题类仅依赖抽象接口Observer,与具体实现解耦。
  • 支持动态增删观察者,扩展性极强(新增设备只需实现Observer接口)。
  • 符合开闭原则,无需修改已有代码即可扩展功能。

总结

场景 不使用观察者模式 使用观察者模式
耦合度 高(直接依赖具体类) 低(依赖抽象接口)
扩展性 差(需修改主题类代码) 优(新增观察者无需修改主题类)
动态管理 不支持运行时增删 观察者支持
代码维护成本 高(重复调用逻辑) 低(统一管理逻辑)

观察者模式通过抽象接口和动态注册机制,有效解决了硬编码调用带来的耦合性问题,是解耦对象间通知关系的经典方案。