今天为大家介绍《head first设计模式》中的观察者模式的C++实现代码。
首先定义三个抽象类Observer、Subject和DisplayElement,代码如下。
//Observer.h
#ifndef _OBSERVER_H_
#define _OBSERVER_H_
#include"head.h"
class Observer
{
public:
Observer(){}
virtual ~Observer(){}//必须的有定义,即{}
virtual void update(float temp,float humi,float press)=0;
};
#endif
//Subject.h
#ifndef _SUBJECT_H_
#define _SUBJECT_H_
#include"head.h"
class Subject
{
public:
virtual void registerObserver(Observer* O)=0;
virtual void removeObserver(Observer* O)=0;
virtual void notifyObservers() const=0;
};
#endif
//DisplayElement.h
#ifndef _DISPLAYELEMENT_H_
#define _DISPLAYELEMENT_H_
#include"head.h"
class DisplayElement
{
public:
DisplayElement(){}
virtual ~DisplayElement()=0{}//必须得有定义,即{}
virtual void display() const=0;
};
#endif
然后是主题类Subject的派生类WeatherData
//WeatherData.h
#ifndef _WEATHERDATA_H_
#define _WEATHERDATA_H_
#include"head.h"
class WeatherData:public Subject
{
private:
list< Observer*> obs;
float temperature;
float humidity;
float pressure;
private:
WeatherData(const WeatherData&);
WeatherData& operator=(const WeatherData&);
public:
WeatherData():temperature(0.0),humidity(0.0),
pressure(0.0){
cout<<"WeatherData"<<endl;
}
~WeatherData()
{
cout<<"~WeatherData"<<endl;
}
virtual void registerObserver(Observer* O)
{
assert(O);
obs.push_back(O);
}
virtual void removeObserver(Observer* O)
{
assert(O);
obs.remove(O);
}
virtual void notifyObservers() const
{
list< Observer*>::const_iterator iter=obs.begin();
for(;iter!=obs.end();iter++)
{
(*iter)->update(temperature,humidity,pressure);
}
}
void measurementsChanged()
{
notifyObservers();
}
void setMeasurements(float temp, float humi, float press)
{
temperature=temp;
humidity=humi;
pressure=press;
measurementsChanged();
}
float getTemperature() const
{
return temperature;
}
float getHumidity() const
{
return humidity;
}
float getPressure() const
{
return pressure;
}
};
#endif
下面是同时继承Observer和DisplayElement的三个派生类。
//CurrentConditionsDisplay.h
#ifndef _CURRENTCONDITIONSDISPLAY_H_
#define _CURRENTCONDITIONSDISPLAY_H_
#include"head.h"
class CurrentConditionsDisplay:public Observer,public DisplayElement
{
private:
shared_ptr<Subject> Weat;
float temperature;
float humidity;
float pressure;
public:
CurrentConditionsDisplay(shared_ptr<Subject> W):Weat(W),
temperature(0.0),humidity(0.0),pressure(0.0)
{
assert(Weat);
cout<<"CurrentConditionsDisplay"<<endl;
Weat->registerObserver(this);
}
~CurrentConditionsDisplay()
{
cout<<"~~CurrentConditionsDisplay"<<endl;
Weat->removeObserver(this);
}
void update(float temp,float humi,float press)
{
temperature=temp;
humidity=humi;
pressure=press;
display();
}
void display() const
{
cout<<"the temperature is "<<temperature<<endl;
cout<<"the humidity is "<<humidity<<endl;
cout<<"the pressure is "<<pressure<<endl;
}
};
#endif
//StatisticsDisplay.h
#ifndef _STATISTICSDISPLAY_H_
#define _STATISTICSDISPLAY_H_
#include"head.h"
class StatisticsDisplay:public Observer,public DisplayElement
{
private:
shared_ptr<Subject> Weat;
float maxtemp;
float mintemp;
float sumtemp;
int numread;
public:
StatisticsDisplay(shared_ptr<Subject> W):Weat(W),
maxtemp(0.0),mintemp(200.0),sumtemp(0.0),numread(0)
{
assert(Weat);
cout<<"StatisticsDisplay"<<endl;
Weat->registerObserver(this);
}
~StatisticsDisplay()
{
Weat->removeObserver(this);
cout<<"~StatisticsDisplay"<<endl;
}
void update(float temp,float humi,float press)
{
sumtemp+=temp;
numread++;
if(temp>maxtemp)
maxtemp=temp;
if(temp<mintemp)
mintemp=temp;
display();
}
void display() const
{
cout<<"maxtemp is "<<maxtemp<<endl;
cout<<"mintemp is "<<mintemp<<endl;
cout<<"avertemp is "<<sumtemp/numread<<endl;
}
};
#endif
//ForecastDisplay.h
#ifndef _FORECASTDISPLAY_H_
#define _FORECASTDISPLAY_H_
#include"head.h"
class ForecastDisplay:public Observer,public DisplayElement
{
private:
shared_ptr<Subject> Weat;
float Curr_press;
float Last_press;
public:
ForecastDisplay(shared_ptr<Subject> W):Weat(W),
Curr_press(0.0),Last_press(0.0)
{
assert(Weat);
cout<<"ForecastDisplay!"<<endl;
Weat->registerObserver(this);
}
~ForecastDisplay()
{
cout<<"~~~ForecastDisplay"<<endl;
Weat->removeObserver(this);
}
void update(float temp,float humi,float press)
{
Last_press=Curr_press;
Curr_press=press;
display();
}
void display() const
{
float comp=Last_press-Curr_press;
if(!(comp>-0.000001&&comp<0.000001))
{
if(comp>0.0)
cout<<"The pressure is declining"<<endl;
else
cout<<"The pressure is rising"<<endl;
}
else
cout<<"The pressure is constant"<<endl;
}
};
#endif
然后是包括本程序头文件的文件。
//head.h
#ifndef _HEAD_H_
#define _HEAD_H_
#include<list>
#include<iostream>
#include<assert.h>
#include<memory>
using namespace std;
#include"DisplayElement.h"
#include"Observer.h"
#include"Subject.h"
#include"CurrentConditionsDisplay.h"
#include"StatisticsDisplay.h"
#include"ForecastDisplay.h"
#include"WeatherData.h"
#endif
最后是主函数实现。
//main.cpp
#include"head.h"
int main()
{
//程序是这样设计的:
//1.先创建一个WeatherData对象(主题),
//2.然后通过主题对象(WeatherData)作为观察者构造函数的参数构造
//观察者对象(包括CurrentConditionsDisplay、StatisticsDisplay以及 )
//3.在创建观察者对象时,在其构造函数中把其加入到主题中。所以在观察者类中
//将包括一个私有的WeatherData类成员,即这就是所谓的组合类。
//4.然后WeatherData对象调用setMeasurements函数时,将会最终调用观察者类的update函数
//(这是由于WeatherData类中有list<Observer*>的私有类型,拿来存放观察者的多个类),同时
//而在update函数中将调用display函数,最后将WeatherData对象调用setMeasurements函数的设置的结果
//展现到界面上。
//5.在观察者类中调用析构函数时将从主题中移除。
shared_ptr<WeatherData> weat(new WeatherData);
shared_ptr<CurrentConditionsDisplay> curr(new CurrentConditionsDisplay(weat));
shared_ptr<StatisticsDisplay> statis(new StatisticsDisplay(weat));
ForecastDisplay fore(weat);
weat->setMeasurements(80.0,70.0,90.0);
weat->setMeasurements(81.0,75.0,89.0);
weat->setMeasurements(81.0,75.0,89.0);
return 0;
}