观察者(Oserver)模式
一、问题的提出
第三方提供了一个类WeatherData,提供的getXXX方法可以取得三个测量值:温度、湿度和气压,每当数据准备好便调用measurementsChanged()方法。现在需要我们实现三个布告板:“目前状况”布告、“气象统计“布告、“天气预报”布告。一旦WeatherData有新的测量,这些布告必须马上更新。(此系统必须可以扩展,让其他开发人员建立定制的布告板,用户可以随心所欲添加或删除任何布告板)
WeatherData接口:
根据要求,可能会有如下实现:
void measurementChanged()
{
float temp = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();
currentConditionDisplay.update(temp, humidity, pressure);
statisticsDisplay.update(temp, humidity, pressure);
forecastDisplay.update(temp, humidity, pressure);
}
缺点:针对具体实现编程,会导致我们以后在增加或删除布告时必须修改程序。
二、认识观察者模式
观察者模式定义了对象之间的一对多依赖,这样一来,当这个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
定义观察者模式:类图
当
两个对象之间松耦合,它们之间依然可以交互(传递数据),但是不清楚彼此实现的细节。观察者模式提供了一种对象设计,让主题和观察者之间松耦合。改变主题或者观察者其中一方,并不会影响另一方。因为
两者是松耦合的,所以
只要他们之间的接口被遵循,我们就可以自由地改变他们。
三、设计气象站
四、实现气象站
头文件:
#ifndef OBSERVER__H
#define OBSERVER__H
#include <vector>
#include <iostream>
using namespace std;
class Observer
{
public:
virtual void update(float temp, float humidity, float pressure) = 0;
void display(); //当布告牌需要显示时调用
};
class Subject
{
public:
virtual void registerObserver(Observer* o) = 0; //添加观察者
virtual void removeObserver(Observer* o) = 0; //删除观察者
virtual void notifyObserver() = 0; //通知所有观察者
};
class WeatherData : public Subject
{
private:
vector<Observer*> m_observers;
float temp;
float humidity;
float pressure;
public:
WeatherData();
// ~WeatherData();
void registerObserver(Observer* o);
void removeObserver(Observer* o);
void notifyObserver();
void measurementsChanged();
void setMeasurements(float temp, float humidity, float pressure);
};
class CurrentConditionsDisplay : public Observer
{
private:
float temp;
float humidity;
Subject* weatherData;
public:
CurrentConditionsDisplay(Subject* weatherData);
void update(float temp, float humidity, float pressure);
void display();
};
#endif
cpp文件
#include "Observer.h"
WeatherData::WeatherData()
{
}
void WeatherData::registerObserver(Observer *o)
{
m_observers.push_back(o);
}
void WeatherData::removeObserver(Observer *o)
{
}
void WeatherData::notifyObserver()
{
for(vector<Observer*>::iterator it=m_observers.begin(); it!=m_observers.end(); ++it)
{
Observer* ob = *it;
ob->update(temp, humidity, pressure);
}
}
void WeatherData::setMeasurements(float temp, float humidity, float pressure)
{
this->temp = temp;
this->humidity = humidity;
this->pressure = pressure;
notifyObserver();
}
CurrentConditionsDisplay::CurrentConditionsDisplay(Subject* weatherData)
{
this->weatherData = weatherData;
weatherData->registerObserver(this);
}
void CurrentConditionsDisplay::update(float temp, float humidity, float pressure)
{
this->temp = temp;
this->humidity = humidity;
display(); //把温度和湿度保存起来,再调用display()
}
void CurrentConditionsDisplay::display()
{
cout<<"Current conditions: "<<temp<<" F degrees and " << humidity << "% humidity"<<endl;
}
测试代码:
#include "Observer.h"
int main()
{
WeatherData wd;
CurrentConditionsDisplay* ccd = new CurrentConditionsDisplay(&wd);
wd.setMeasurements(33.2, 22.1, 53.2);
wd.setMeasurements(1.1, 2.2, 3.3);
wd.setMeasurements(3.2, 1.3, 5.5);
delete ccd;
getchar();
}
代码中只实现了一个布告牌。后面要添加的布告牌只要实现接口即可。
四、总结
针对接口编程,尽可能的封装。