观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖着都会收到通知并自动更新。
当两个对象之间松耦合,他们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计,让主题和观察者之间松耦合。我们可以独立复用主题和观察者,如果我们在其他地方需要使用主题或观察者,可以轻易地复用,因为二者并非紧耦合。改变主题或者观察者其中一方,并不会影响另一方。因为两者是松耦合的,所以只要他们之间的接口仍被遵守,我们就可以*地改变他们。
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低。
书上的例子是一个天气公告牌,代码如下:
Weather.h
#include <vector> #include <string> class Observer { public: virtual void update(float temp) = 0; }; class DisplayElement { public: virtual void display() = 0; }; class Subject { public: virtual void registerObserver(Observer& o) = 0; virtual void removeObserver(Observer& o) = 0; virtual void notifyObservers() = 0; }; class WeatherDate : public Subject { public: ~WeatherDate(); void registerObserver(Observer& o); void removeObserver(Observer& o); void notifyObservers(); void measurementsChanged(); void setMeasurements(float temp); private: std::vector<Observer*> observerList; float temperature = 0; }; class WeatherBoard01: public Observer, DisplayElement { public: WeatherBoard01(Subject& weatherDate, std::string name); ~WeatherBoard01(); void update(float temp); void display(); private: std::string name = ""; float temperature = 0; Subject* weatherDate = nullptr; }; void weatherTest();
Weather.cpp
#include <iostream> #include "Weather.h" WeatherDate::~WeatherDate() { for (auto it: observerList) { delete it; } } void WeatherDate::registerObserver(Observer &o) { observerList.push_back(&o); } void WeatherDate::removeObserver(Observer &o) { for (auto it = observerList.begin(); it != observerList.end(); it++) { if (*it == &o) { observerList.erase(it); break; } } } void WeatherDate::notifyObservers() { for (auto it: observerList) { it->update(temperature); } } void WeatherDate::measurementsChanged() { notifyObservers(); } void WeatherDate::setMeasurements(float temp) { temperature = temp; measurementsChanged(); } WeatherBoard01::WeatherBoard01(Subject &weatherDate, std::string name) { this->weatherDate = &weatherDate; this->name = name; weatherDate.registerObserver(*this); weatherDate.notifyObservers(); } WeatherBoard01::~WeatherBoard01() { delete weatherDate; } void WeatherBoard01::update(float temp) { temperature = temp; display(); } void WeatherBoard01::display() { std::cout<<"WeatherBoard01("<<name<<"): "<<temperature<<std::endl; }
需要注意的东西大概:
1. 如果类成员变量是指针vector,应该如何析构?
2. 抽象类不能直接作为函数的参数。那么是传引用更好还是传指针更好?
3. vector的方法待学习。
blog的观察者模式实现了一个博客和订阅者的关系,具体见:https://blog.csdn.net/wuzhekai1985/article/details/6674984
两者区别在于:
1. blog里的代码没有具体实现析构函数。但是对于有指针成员的类,应该手动delete。所以还是不知道指针vector怎么析构。
2. 一个好的思路:观察者对主题的指针也可以设计成指针vector,这样的话就允许一个观察者同时观察多个主题,把一对多的关系扩展为多对多的关系。