《Head First设计模式》 观察者模式 C++实现

    技术2025-12-24  18

    Head First设计模式 观察者模式 C++实现

    书中简介:出版者+订阅者=观察者模式,出版者改称为“主题”(Subject),订阅者改称为“观察者”(Observer)。简单说,就是一群观察者观察同一份主题对象,类图如下:

    主题对象内部一旦发生数据变化时,主题对象就会通知已经订阅它的观察者们,从而让观察者们及时更新数据。

    观察者模式定义了对象之间一对多的依赖关系,这样一来它的所有依赖者都会收到通知并自动更新。这样的设计有个好处,那就是让主题和观察者之间松耦合。

    一般而言,主题对象内部会有一个vector容器,当作观察者对象集合,用来存放注册在此的观察者对象。同时,观察者们也会有一个主题(Subject)类型的指针,指向所观察的主题(Subject)对象。【注】:我们声明主题(Subject)类和观察者(Observer)类都为接口或抽象类(遵循面向接口编程,而不是具体类),类图如下:

    书中举的例子是设计气象站,简单说,我们有一个专门检测和预测天气的装置(WeatherData),它只做检测和预测的事,当数据有变化时就会通知(调用notify_observer()方法)它的观察者们(CurrentConditionDisplay, ForecastDisplay),notify_observer()方法内部就是遍历vector容器,调用注册在此的观察者(Observer)们的update()方法。类图如下:

    我们让具体的主题(Subject)类WeatherData拥有抽象的Observer接口,在具体中有抽象,这样会让我们后期的扩展变得容易很多,哪怕以后还会新加入一个ThirdDisplay,我们在代码级别上不需要改动WeatherData类,只需要让ThirdDisplay实现Observer接口即可。这样会使我们的代码很有弹性,我们在设计时要考虑到,什么东西是会经常改变的,什么东西是不变的。

    在书上的例子中,WeatherData可以说是不变的,而我们的Display将来会扩展很多,所以我们可以将不经常改变的对象稍微写“死”一点,留下可以改变的空间,也就是组合(委托)手段啦。

    实现代码如下:

    #include <iostream> #include <vector> using namespace std; // 观察者类接口 class Observer { public: virtual void update()=0; }; // 主题类接口 class Subject { public: virtual void register_observer(Observer*)=0; virtual bool remove_observer(Observer*)=0; virtual void notify_observers()=0; }; // 天气数据类 class WeatherData : public Subject { private: float m_temperature; float m_humidity; float m_pressure; vector<Observer* > m_vct; public: void register_observer(Observer *o) { m_vct.push_back(o); } bool remove_observer(Observer *o) { // 遍历vector for(auto ite = m_vct.begin(); ite!=m_vct.end(); ite++) { if((*ite) == o) { m_vct.erase(ite); return true; } } return false; } void notify_observers() { // 遍历vector for(auto ite = m_vct.begin(); ite!=m_vct.end(); ite++) { (*ite)->update(); } } void set_measurements(float t, float h, float p) { m_temperature = t; m_humidity = h; m_pressure = p; notify_observers(); } }; // 近况公示牌 class CurrentConditionsDisplay : public Observer { private: WeatherData *m_wd; public: CurrentConditionsDisplay(WeatherData *wd): m_wd(wd) { m_wd->register_observer(this); } void update() { cout << "I'm currentConditions ready. I'm watching " << m_wd << endl; } }; // 预测公示牌 class ForecastDisplay : public Observer { private: WeatherData *m_wd; public: ForecastDisplay(WeatherData *wd): m_wd(wd) { m_wd->register_observer(this); } void update() { cout << "I'm forecastDisplay ready. I'm watching " << m_wd << endl; } }; int main() { WeatherData *wd = new WeatherData(); CurrentConditionsDisplay *cd = new CurrentConditionsDisplay(wd); ForecastDisplay *fd = new ForecastDisplay(wd); wd->set_measurements(1.01, 2.02, 3.03); // 删除ForecastDisplay wd->remove_observer(fd); wd->set_measurements(1, 1, 1); return 0; }
    Processed: 0.018, SQL: 9