定义:
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
场景:
我们有一个气象站,我们通过WeatherData获取气象站的最新数据,并更新布告板上的数据。我们定义了两个布告板,一个是温度计,显示最新的温度,另一个布告板就是显示当前的所有温度、湿度和气压的最新数据。
类图:
c++代码如下:
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
using namespace std;
class Observer;
// 主题
class Subject
{
public:
virtual void registerObserver(Observer* o) = 0;
virtual void removeObserver(Observer* o) = 0;
virtual void notifyObserver() = 0;
float getTemperature();
float getHumidity();
float getPressure();
protected:
float m_temperature;
float m_humidity;
float m_pressure;
};
// 观察者
class Observer
{
public:
Observer(Subject* pWeaterData);
virtual ~Observer() {};
virtual void update() = 0;
Subject* getWeaterData();
protected:
Subject* m_weaterData;
};
class DisplayElement
{
public:
virtual void display() = 0;
};
class WeatherData:public Subject
{
public:
WeatherData();
~WeatherData();
void registerObserver(Observer* o);
void removeObserver(Observer* o);
void notifyObserver();
void measurementsChanged();
void setMeasurements(float temperature, float humidity, float pressure);
private:
list<Observer*> m_lObserver;
};
// 当前条件显示
class CurrentConditionsDisplay:public Observer,public DisplayElement
{
public:
CurrentConditionsDisplay(Subject* pWeaterData);
~CurrentConditionsDisplay();
void update();
void display();
private:
float m_template; // 温度
float m_humidity; // 湿度
float m_pressure; // 气压
};
// 温度计
class Thermometer:public Observer,public DisplayElement
{
public:
Thermometer(Subject* pWeaterData);
~Thermometer();
void update();
void display();
private:
float m_template; // 温度
};
float Subject::getTemperature()
{
return m_temperature;
}
float Subject::getHumidity()
{
return m_humidity;
}
float Subject::getPressure()
{
return m_pressure;
}
Observer::Observer(Subject* pWeaterData)
{
m_weaterData = pWeaterData;
}
Subject* Observer::getWeaterData()
{
return m_weaterData;
}
WeatherData::WeatherData()
{
m_temperature = 0;
m_humidity = 0;
m_pressure = 0;
}
WeatherData::~WeatherData()
{
list<Observer*>::iterator iter, temp;
for (iter=m_lObserver.begin(); iter!=m_lObserver.end(); ++iter)
{
delete (*iter);
}
m_lObserver.clear();
}
void WeatherData::registerObserver(Observer* o)
{
m_lObserver.push_back(o);
}
void WeatherData::removeObserver(Observer* o)
{
list<Observer*>::iterator iter;
iter = std::find(m_lObserver.begin(), m_lObserver.end(), o);
if (m_lObserver.end() != iter)
{
m_lObserver.erase(iter);
}
}
void WeatherData::notifyObserver()
{
list<Observer*>::iterator iter;
for (iter=m_lObserver.begin(); iter!=m_lObserver.end(); ++iter)
{
(*iter)->update();
}
}
void WeatherData::measurementsChanged()
{
notifyObserver();
}
void WeatherData::setMeasurements(float temperature, float humidity, float pressure)
{
m_temperature = temperature;
m_humidity = humidity;
m_pressure = pressure;
measurementsChanged();
}
CurrentConditionsDisplay::CurrentConditionsDisplay(Subject* pWeaterData):Observer(pWeaterData)
{
pWeaterData->registerObserver(this);
}
CurrentConditionsDisplay::~CurrentConditionsDisplay()
{
m_weaterData = NULL;
}
void CurrentConditionsDisplay::update()
{
m_template = m_weaterData->getTemperature();
m_humidity = m_weaterData->getHumidity();
m_pressure = m_weaterData->getPressure();
display();
}
void CurrentConditionsDisplay::display()
{
printf("Current conditions %f0.2F degrees and %0.2f%s humidity and pressure %0.2f\n",m_template,m_humidity,"%",m_pressure);
}
Thermometer::Thermometer(Subject* pWeaterData):Observer(pWeaterData)
{
pWeaterData->registerObserver(this);
}
Thermometer::~Thermometer()
{
m_weaterData = NULL;
}
void Thermometer::update()
{
m_template = m_weaterData->getTemperature();
display();
}
void Thermometer::display()
{
printf("Current conditions %f0.2F degrees\n",m_template);
}
int main()
{
WeatherData* pWeatherData = new WeatherData();
CurrentConditionsDisplay* pCurrentConditionsDisplay = new CurrentConditionsDisplay(pWeatherData);
Thermometer* pThermometer = new Thermometer(pWeatherData);
pWeatherData->setMeasurements(123,456,789);
// 当移除观察者后,需要手动释放内存
pCurrentConditionsDisplay->getWeaterData()->removeObserver(pCurrentConditionsDisplay);
pWeatherData->setMeasurements(789,456,123);
// 当再次注册后,内存交由主题管理
pCurrentConditionsDisplay->getWeaterData()->registerObserver(pCurrentConditionsDisplay);
pWeatherData->setMeasurements(135,257,479);
delete pWeatherData;
return 0;
}
运行后结果如下:
Current conditions 123.000F degrees and 456.00% humidity and pressure 789.00
Current conditions 123.00F degrees
Current conditions 789.00F degrees
Current conditions 135.00F degrees
Current conditions 135.00F degrees and 257.00% humidity and pressure 479.00
参考资料:《Head First 设计模式》