1. 程式人生 > >C++觀察者模式

C++觀察者模式

最近在看《headfirst 設計模式》這本書,裡面講的設計模式是基於java語言的,看完後我會利用C++來實現以加深自己的理解。先呈上觀察者模式:

觀察者模式定義了物件間的一對多依賴,這樣一來,當一個物件改變狀態時,它的所有依賴者都會收到通知並自動更新。它主要包括了一個主題和若干個觀察者,只要一個物件註冊成為觀察者,主題狀態改變時,這個物件就能收到通知。模型如下:


這裡借用了《headfirst 設計模式》的介紹,C++裡面沒有介面,但是C++支援多重繼承,所以可以用抽象類來代替介面;程式碼實現如下:

#include "stdafx.h"
#include <iostream>
#include <list>
#include <iomanip>
using namespace std;
class Observer
{
public:
	virtual void update(float tmp,float humidity,float pressure)=0;
};
class Subject
{
public:
	virtual void registerObserver(Observer* o)=0;
	virtual void removeObserver(Observer* o)=0;
	virtual void notifyObservers()=0;
};

class WeatherData :public Subject
{
public:
	void registerObserver(Observer* o)
	{
		observeList.push_back(o);
	}
	void removeObserver(Observer* o)
	{
		observeList.remove(o);
	}
	void notifyObservers()
	{
		for (list<Observer*>::iterator it=observeList.begin();it!=observeList.end();++it)
		{
			(*it)->update(temprature,humidity,pressure);
		}
	}
	void measurementsChanged()
	{
		notifyObservers();
	}
	void setMeasurements(float temprature,float humidity,float pressure)
	{
		this->temprature=temprature;
		this->humidity=humidity;
		this->pressure=pressure;
		measurementsChanged();
	}
private:
	float temprature;
	float humidity;
	float pressure;
	list<Observer*> observeList;
};

class CurrentConditonDisplay:public Observer
{
public:
	CurrentConditonDisplay(Subject *weatherdata)
	{
		this->myWeatherData=weatherdata;
		Subscribe();
	}
	void update(float tmp,float humidity,float pressure)
	{
		this->temprature=tmp;
		this->humidity=humidity;
		display();
	}
    void display()
	{
		cout<<"Current Condition: "<<setprecision(3)<<showpoint<<temprature<<"F degree and "<<setprecision(3)<<humidity<<"% humidity"<<endl;
	}
	void Subscribe()
	{
		myWeatherData->registerObserver(this);
	}
	void Unsubscribe()
	{
		myWeatherData->removeObserver(this);
	}
private:
	float temprature;
	float humidity;
        Subject *myWeatherData;

};

class StatisticDisplay:public Observer
{
public:
	StatisticDisplay(Subject *weatherdata)
	{
		this->myWeatherData=weatherdata;
		Subscribe();
		this->maxTemprature=-1000;
		this->minTemprature=1000;
	}
	void update(float tmp,float humidity,float pressure)
	{
		this->minTemprature=min(minTemprature,tmp);
		this->maxTemprature=max(maxTemprature,tmp);
		
		display();
	}
	void display()
	{
		cout<<"Max/Min Temperature= "<<setprecision(3)<<showpoint<<maxTemprature<<"/"<<setprecision(3)<<minTemprature<<endl;
	}
	void Subscribe()
	{
		myWeatherData->registerObserver(this);
	}
	void Unsubscribe()
	{
		myWeatherData->removeObserver(this);
	}
private:
	float minTemprature;
	float maxTemprature;
	Subject *myWeatherData;

};
int _tmain(int argc, _TCHAR* argv[])
{
	WeatherData *myWeatherData=new WeatherData;
	CurrentConditonDisplay conditionDisplay(myWeatherData);  //預設成為觀察者

	StatisticDisplay statisticDisplay(myWeatherData);      //預設成為觀察者

	myWeatherData->setMeasurements(80,65,30.4f);
	myWeatherData->setMeasurements(82,70,29.2f);

	conditionDisplay.Unsubscribe();         //取消訂閱,不再是觀察者
	myWeatherData->setMeasurements(78,90,29.2f);
	delete myWeatherData;
	return 0;
}
執行結果如下: