設計模式-Observer
1. 解決的問題:
假如現在要編寫一個天氣預報的公布欄, 公布欄有兩種顯示方式, 一種是圖像方式顯示, 一種是表格形式顯示.
2. 問題分析:
應該根據數據與現實分離的原則將天氣預報數據和現實形式分別封裝起來,
今后可能增加其他的顯示形式;
天氣預報數據發生變化后,需要對所有的顯示形式進行更新.
3. UML圖與代碼實現:
1)用Push的方式更新Observer數據, 通過Subject對Observer進行注冊:
2)用Pull的方式更新Observer數據, Observer自己進行注冊:1: //這個例子中WeatherData就是Subject, 而WeatherView則是Observer,
2: //這里WeatherView中沒有包含到WeatherData的引用,
3: //因此這里是Subject用push的方法向Observer發送數據;
4: //并且注冊和反注冊Observer的時候都是由Subject(WeatherData)執行的
5:6: #include <iostream>7: #include <vector>8: #include <algorithm>9:10: using namespace std;11:12: class WeatherData;
13:14: class WeatherView
15: {16: public:
17: void Update(int temp, int hum)18: {19: temperature = temp;20: humidity = hum;21: };22: virtual void Display()23: {24: cout << "temperature = " << temperature << ", humidity = " << humidity << endl;25: }26:27: private:
28:29: int temperature;
30: int humidity;
31: };32:33: class GraphicView: public WeatherView34: {35: public:
36: void Display()
37: {38: cout << "====--Weather Report With Graphic Format--===="<< endl;
39: WeatherView::Display();40: }41: };42:43: class TableView: public WeatherView44: {45: public:
46: void Display()
47: {48: cout << "====--Weather Report With Table Format--===="<< endl;
49: WeatherView::Display();50: }51: };52:53: class WeatherData
54: {55: public:
56: void SetWeahterData(int temp, int hum)57: {58: temperature = temp;59: humidity = hum;60: NotifyObservcer();61: }62:63: void RegisterObserver(WeatherView* obs)
64: {65: obsList.push_back(obs);66: }67:68: void RemoveObserver(WeatherView* obs)
69: {70: vector<WeatherView*>::iterator it;71: it = find(obsList.begin(), obsList.end(), obs);72: if (it != obsList.end())
73: obsList.erase(it);74: }75:76: private:
77: vector<WeatherView*> obsList;78: int temperature;
79: int humidity;
80: void NotifyObservcer()
81: {82: vector<WeatherView*>::iterator it;83: for(it = obsList.begin(); it < obsList.end(); it++)
84: {85: (*it)->Update(temperature, humidity);86: }87: }88: };89:90:91: int main()
92: {93: WeatherData *wd = new WeatherData();
94: GraphicView *gv = new GraphicView();
95: TableView *tv = new TableView();
96:97: wd->RegisterObserver(gv);98: wd->RegisterObserver(tv);99: wd->SetWeahterData(23,45);100: gv->Display();101: tv->Display();102:103: wd->RemoveObserver(gv);104: wd->SetWeahterData(67,89);105: gv->Display();106: tv->Display();107:108: return 0;
109: }
1: #ifndef WEATHERDATA_HPP_INCLUDED2: #define WEATHERDATA_HPP_INCLUDED3: #include <iostream>4: #include <vector>5:6: #include "WeatherView.hpp"
7:8: class WeatherData
9: {10: public:
11: void SetWeahterData(int temp, int hum)12: {13: temperature = temp;14: humidity = hum;15: NotifyObservcer();16: }17:18: int GetTemperature()
19: {20: return temperature;
21: }22:23: int GetHumidty()
24: {25: return humidity;
26: }27:28: void RegisterObserver(WeatherView* obs);
29: void RemoveObserver(WeatherView* obs);
30:31: private:
32: vector<WeatherView*> obsList;33: int temperature;
34: int humidity;
35: void NotifyObservcer();
36: };37:38: #endif
=================
1: #ifndef WEATHERVIEW_HPP_INCLUDED2: #define WEATHERVIEW_HPP_INCLUDED3:4: #include <iostream>5: #include <vector>6: #include <algorithm>7:8:9: class WeatherData;
10:11: using namespace std;12:13: class WeatherView
14: {15: public:
16: WeatherView(WeatherData* wd);17:18: void Update();
19: void Register();
20: void Unregister();
21:22: virtual void Display()23: {24: cout << "temperature = " << temperature << ", humidity = " << humidity << endl;25: }26:27: private:
28: WeatherData* wd;29: int temperature;
30: int humidity;
31: };32:33: class GraphicView: public WeatherView34: {35: public:
36: GraphicView(WeatherData* wd);37: void Display()
38: {39: cout << "====--Weather Report With Graphic Format--===="<< endl;
40: WeatherView::Display();41: }42: };43:44: class TableView: public WeatherView45: {46: public:
47: TableView(WeatherData* wd);48: void Display()
49: {50: cout << "====--Weather Report With Table Format--===="<< endl;
51: WeatherView::Display();52: }53: };54:55: #endif
===================
1: //這個例子中WeatherData就是Subject, 而WeatherView則是Observer,
2: //這里WeatherView中有一個包含到WeatherData的指針,
3: //因此這里是Observer用pull的方法主動向Observer索取數據;
4: //并且注冊和反注冊都是Observer自己執行的
5: #include <iostream>6: #include <vector>7: #include <algorithm>8: #include "WeatherView.hpp"
9: #include "WeatherData.hpp"
10:11: void WeatherData::RegisterObserver(WeatherView* obs)
12: {13: obsList.push_back(obs);14: }15:16: void WeatherData::RemoveObserver(WeatherView* obs)
17: {18: vector<WeatherView*>::iterator it;19: it = find(obsList.begin(), obsList.end(), obs);20: if (it != obsList.end())
21: obsList.erase(it);22: }23:24: void WeatherData::NotifyObservcer()
25: {26: vector<WeatherView*>::iterator it;27: for(it = obsList.begin(); it < obsList.end(); it++)
28: {29: (*it)->Update();30: }31: }32:33:34: WeatherView::WeatherView(WeatherData* pwd)35: {36: wd = pwd;37: }38:39: void WeatherView::Update()
40: {41: temperature = wd->GetTemperature();42: humidity = wd->GetHumidty();43: };44:45: void WeatherView::Register()
46: {47: wd->RegisterObserver(this);
48: };49:50: void WeatherView::Unregister()
51: {52: wd->RemoveObserver(this);
53: };54:55: GraphicView::GraphicView(WeatherData* pwd) : WeatherView(pwd)56: {57:58: }59:60: TableView::TableView(WeatherData* pwd) : WeatherView(pwd)61: {62:63: }64: int main()
65: {66: WeatherData *wd = new WeatherData();
67: GraphicView *gv = new GraphicView(wd);
68: gv->Register();69: TableView *tv = new TableView(wd);
70: tv->Register();71:72: wd->SetWeahterData(23,45);73: gv->Display();74: tv->Display();75:76: gv->Unregister();77: wd->SetWeahterData(67,89);78: gv->Display();79: tv->Display();80:81: return 0;
82: }
======================
上面兩種實現的執行結果如下:
1: ====--Weather Report With Graphic Format--====2: temperature = 23, humidity = 453: ====--Weather Report With Table Format--====4: temperature = 23, humidity = 455: ====--Weather Report With Graphic Format--====6: temperature = 23, humidity = 457: ====--Weather Report With Table Format--====8: temperature = 67, humidity = 89
4. Push還是Pull?
對于上面的例子, Observer中的數據是從Subject中一次性全部更新的(temperature 和 humidity), 這種更新數據的方式便是push;然而如果WeatherData中的數據量非常大, 而有些Observer并不需要所有的數據, 比如現在要新增兩個顯示方式,一個是只顯示溫度,而另一個則只顯示濕度, 這樣的話就沒有必要讓所有的Observer都得到所有的數據. 最好的方式是Observer能根據自己的需要從Subject中去取得數據,這種更新數據的方式便是Pull. Observer模式中Push和Pull兩種設計方法體現在具體的程序中就是Observer中的Update()接口參數不同, 對于Push模式, Update()接口的參數通常就是需要Push的那些數據,比如這里的溫度和濕度; 對于Pull模式, Update()的參數是Subject的一個引用, 然后Subject提供一些數據接口,由Observer通過這些接口自己取得所需要的數據.
5. 總結:
1. Strategy 模式定義:
定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更新.
2. 體現的設計原則:
- 將數據與現實分別封裝;
- 多使用組合,少使用繼承;
- 面向接口編程,而不面向實現編程;
3. UML圖:
4. 要點:
- Strategy 基類需要定義出可供Client使用的一些算法接口;
- 可以隨時根據需要增加 Strategy 而不會影響到Client;
- Client 里面需要包含對 Strategy 的引用;
- Client 可以隨時更換 Strategy;
6. 理解:
- Observer模式是解決對象之間數據傳遞問題的一種模式;
- Observer的注冊可以由Subject執行也可以由Observer自己執行;
- 和Strategy模式的比較:
1) Observer模式中Observer 中定義了 Update()接口供 Subject調用; 而Strategy模式中,Strategy定義了AlgrithmInterface()供Client調用;
2) Observer模式中Subject和Observer是一對多的關系, 因此Subject是一次調用n個Observer的Update()接口;而Strategy模式中Client與Strategy之間是一對一的關系, Client 就是調用指定的那個Strategy的AlgrithmInterface();
3) 也正因為這種對應關系的不同, 在Observer模式中, Subject可以Register或者Remove某個Observer, 而Strategy模式中通常只是set某個Strategy
原文地址: http://blog.csdn.net/zhongjiekangping/article/details/6903017