观察者模式的定义
定义了对象之间的一对多依赖,都一个对象改变状态时,它的所有依赖都会收到通知并自动更新。
可以通过报纸的订阅来理解观察者模式,将报纸的出版者称为“主题Subject”,订阅者称为“观察者Observer”。
对于已经订阅的观察者,主题对象的数据一旦改变,会将新的数据以某种形式送到观察者手上。
一个错误的示例:
class WeatherData {
public:
void measurementsChanged() {
m_temp = getTemperature();
m_humidity = getHumidity();
m_pressure = getPressure();
currentConditionDisplay.update(m_temp, m_humidity, m_pressure);
stattisticDisplay.update(m_temp, m_humidity, m_pressure);
forecastDisplay.update(m_temp, m_humidity, m_pressure);
private:
float m_temp = 0;
float m_humidity = 0;
float m_pressure = 0;
Observer observer[3] = {currentConditionDisplay, stattisticDisplay, forecastDisplay};
}
以上实现存在多个问题:
1.针对具体实现编程,而非针对接口;
2.对于每个新的observer,都需要修改代码,无法运行时动态增减observer;
3.observer没有实现共同的接口;
4.没有封装可能改变的部分;
5.侵犯了WeatherData类的封装;
观察者模式引入了一个新的设计原则:为了交互对象之间的松耦合设计而努力。
好的设计:
class ISubject {
public:
virtual void registerObserver(Observer o);
virtual void removeObserver(Observer o);
virtal void notifyObserver(Observer o);
}
class IObserver {
public:
virtual void update(Data data);
}
class IDisplay {
public:
virtual void display();
}
class WeatherData : public ISubject {
private:
float m_temp;
float m_humidity;
float m_pressure;
vector<Observer> observerArray;
public:
WeatherData(): m_temp(0), m_humidity(0), m_pressure(0), observerArray(vector<Observer)()) {};
void registerObserver(Observer o) {
observerArray.add(o);
}
void removeObserver(Observer o) {
observerArray.delete(o);
}
void notifyObservers(Observer o) {
for ( from begin to end) {
o.update(data);
}
void measurementsChanged() {
notifyObserver();
}
void setMeasurements(Data data) {
this.temp = //..
}
}
class CurrentConditionDisplay : public Observer, public DisplayElment {
private:
Data data;
WeatherData weatherData;
public:
CurrentConditionDisplay(ISubject weatherData) {
this.weatherData = weatherData.data;
weatherData.registerObject(this);
}
void update(Data data) {
this.data = data;
display();
}
void display() {
//...
}
}
main.cpp
WeatherData weatherData;
CurrentConditionDisplay cd(weatherData);
StaticDisplay sd(weatherData);
ForecastDisplay fd(weatherData);
Data date(1,2,3);
weatherData.setMeasurement(data);