適用問題:
試想現在要設計一個提供天氣資訊的app,當中可能會需要這樣的函式:
void measurementsChanged(){
float temp = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();
currentConditionDisplay.update(temp, humidity, pressure);
statisticsDisplay.update(temp, humidity, pressure);
forecastDisplay.update(temp, humidity, pressure);
}
首先我們需要獲取目前的氣溫、濕度、氣壓等資訊,接著要將這些資訊顯示,但這樣的寫法有著缺點,那就是若我們要增加顯示就又必須寫一個函式讓顯示器進行更新,只能修改程式而不能在run-time下新增或減少,顯然不是太好的寫法。想想訂報紙的情況,報商會每天印製報紙,客戶則向報商進行訂閱,報商有義務每天送報紙給客戶,客戶若不想再看則也能取消訂閱,而這就是觀察者模式。(Publisher + Subscriber = Observer Pattern)
觀察者模式定義:
"The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically" (觀察者模式定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽某一個主題物件。這個主題物件狀態發生變化時,會通知所有觀察者物件使它們能自動更新自己)
觀察者模式原則:
1. Strive for loosely coupled designs between objects that interact. (發佈者與訂閱者沒有強耦合,不清楚彼此細節仍能正常通訊)
觀察者模式基本UML: Subject -> Observer 的關係是一對多。
如此的設計當有新的訂閱者出現時,發佈者的程式碼不需要做任何修改,同樣發佈者需要改變時,也不會影響到之前的訂閱者。
範例:
上面的氣象資訊例子。
Subject's code (C++):
// The Abstract Subject
class ISubject{
private:
float m_humidity;
float m_temperature;
float m_pressure;
list<iobserver> m_obs;
public:
virtual void registerOb(IObserver* ob) = 0;
virtual void removeOb(IObserver* ob) = 0;
virtual void notifyOb() = 0;
};
// The Concrete Subject
class WeatherData: public ISubject{
public:
void SensorDataChange(float a,float b,float c){
m_humidity = a;
m_temperature = b;
m_pressure = c;
notifyOb();
}
void registerob(IObserver* ob){
m_obs.push_back(ob);
}
void removeob(IObserver* ob){
m_obs.remove(ob);
}
protected:
void notifyOb(){
list<iobserver>::iterator pos = m_obs.begin();
while (pos != m_obs.end()){
((IObserver* )(*pos))->update(m_humidity,m_temperature,m_pressure);
(dynamic_cast<IDisplay*>(*pos))->show();
++pos;
}
}
}
參考資料:
1. Head First Design Patterns
2. JavaScript設計模式與開發實踐 (博碩出版)
沒有留言:
張貼留言