## 模式定義 ? ? ? ?
? ? ? 觀察者模式定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知并自動更新。
## 模式結構:
?????
## 舉例:
? ? ? 氣象系統有三個部分分別是氣象站(獲取實際氣象數據的物理裝置),WeatherData對象(用來追蹤來自氣象站的數據,并更新布告板)和布告板(顯示目前天氣狀況給用戶看)。WeatherData對象知道如何根物理氣象站聯系,以取得更新信息。WeatherData對象會隨機更新三個布告板的顯示:目前狀況(溫度,濕度,氣壓)、氣象統計和天氣預報。我們的工作是建立一個 應用,利用WeatherData對象取得數據,并更新三個布告板:目前狀況、氣象統計和天氣預報。
## 設計UML:

## 代碼實現及執行結果:
~~~
#include <iostream>
#include <list>
using namespace std;
//以下是觀察者和主題的基類,其中DisplayElement是一個抽象類,用來//使子類實現顯示功能
classObserver
{
public:
virtual ~Observer(){};
virtual void update(float temp, floathumidity, float pressure){};
};
classDisplayElement
{
public:
virtual ~DisplayElement(){};
virtual voiddisplay() = 0;
};
classSubject
{
public:
virtual ~Subject(){};
virtual voidregsiterObserver(Observer* o){} ;
virtual voidremoveObserver(Observer* o){};
virtual voidnotifyObserver(){};
};
//以下是WeatherData類,實現了注冊,刪除和通知觀察者的功能。
classWeatherData : public Subject
{
public:
void regsiterObserver(Observer* o)
{
observers.push_back(o);
}
void removeObserver(Observer* o)
{
observers.remove(o);
}
void notifyObservers()
{
list<Observer*>::iteratoriter = observers.begin();
for(; iter != observers.end(); ++iter)
{
Observer*observer = *iter;
observer->update(tempreature,humidity, pressure);
}
}
void measurementsChanged()
{
notifyObservers();
}
void setMeasurements(floattemp, float humid, floatpres)
{
tempreature= temp;
humidity= humid;
pressure= pres;
measurementsChanged();
}
private:
list<Observer*>observers;
float tempreature;
float humidity;
float pressure;
};
//以下是CurrentConditionsDisplay布告板的實現,主要功能為申請注冊,實時更新和顯示。
classCurrentConditionsDisplay : public Observer, public DisplayElement
{
public:
CurrentConditionsDisplay(Subject*weather_Data)
{
weatherData= weather_Data;
weatherData->regsiterObserver(this);
}
void update(floattemp, float humid, floatpres)
{
tempreature= temp;
humidity= humid;
display();
}
void display()
{
cout<< "Current conditions: "<< tempreature
<<"F degree and " << humidity<< "% humidity" <<endl;
}
private:
float tempreature;
float humidity;
Subject*weatherData;
};
//客戶代碼
intmain()
{
WeatherData*weatherData = new WeatherData();
CurrentConditionsDisplay*currentConditionsDisplay =
new CurrentConditionsDisplay(weatherData);
weatherData->setMeasurements(80,65, 30.4f);
weatherData->setMeasurements(82,70, 29.2f);
weatherData->setMeasurements(78,90, 29.2f);
return 0;
}
~~~
執行結果:
**Current conditions: 80F degree and 65% humidity**
**Current conditions: 82F degree and 70% humidity**
**Current conditions: 78F degree and 90% humidity**
**請按任意鍵繼續.. .**
? ? ? 如果還要實現StatisticsDisplay和forecastDisplay或者第三方布告板,只要創建相應類,并且完成祖冊即可。
## 設計原則
? ? ? 設計原則4.為了交互對象之間的松耦合設計而努力。如本例中任何時候我們可以增加新的觀察者,因為主題唯一依賴的東西是一個實現Observer接口的對象列表,所以我們可以隨時增加觀察者。有新類型出現時,主題代碼無需改變。只要在新類里實現觀察者接口,然后注冊為觀察者即可。
? ? ? 設計原則1([http://blog.csdn.net/walkerkalr/article/details/28422609](http://blog.csdn.net/walkerkalr/article/details/28422609))的應用:在觀察者模式,會改變的是主題的狀態,以及觀察者的數目和類型。用這個模式,你可以改變依賴于主題狀態的對象,卻不必改變主題。
? ? ? 設計原則2的應用:主題和觀察者都使用接口。觀察者利用主題的接口向主題注冊。而主題利用觀察者接口通知觀察者。這樣可以讓兩者之間運作正常,又同時具有松耦合的優點。
? ? ? 設計原則3的應用:觀察者模式利用“組合”將許多觀察者組合進主題中。對象之間的這種關系不是通過集成產生的,而是在運行時利用組合的方式產生的。
參考:Head First設計模式