設計模式-Observer
1. 解決的問題:
假如現(xiàn)在要編寫一個天氣預報的公布欄, 公布欄有兩種顯示方式, 一種是圖像方式顯示, 一種是表格形式顯示.
2. 問題分析:
應該根據(jù)數(shù)據(jù)與現(xiàn)實分離的原則將天氣預報數(shù)據(jù)和現(xiàn)實形式分別封裝起來,
今后可能增加其他的顯示形式;
天氣預報數(shù)據(jù)發(fā)生變化后,需要對所有的顯示形式進行更新.
3. UML圖與代碼實現(xiàn):
1)用Push的方式更新Observer數(shù)據(jù), 通過Subject對Observer進行注冊:

1: //這個例子中WeatherData就是Subject, 而WeatherView則是Observer,
2: //這里WeatherView中沒有包含到WeatherData的引用,
3: //因此這里是Subject用push的方法向Observer發(fā)送數(shù)據(jù);
4: //并且注冊和反注冊Observer的時候都是由Subject(WeatherData)執(zhí)行的
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 WeatherView
34: {
35: public:
36: void Display()
37: {
38: cout << "====--Weather Report With Graphic Format--===="<< endl;
39: WeatherView::Display();
40: }
41: };
42:
43: class TableView: public WeatherView
44: {
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: }
2)用Pull的方式更新Observer數(shù)據(jù), Observer自己進行注冊:

1: #ifndef WEATHERDATA_HPP_INCLUDED
2: #define WEATHERDATA_HPP_INCLUDED
3: #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_INCLUDED
2: #define WEATHERVIEW_HPP_INCLUDED
3:
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 WeatherView
34: {
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 WeatherView
45: {
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索取數(shù)據(jù);
4: //并且注冊和反注冊都是Observer自己執(zhí)行的
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: }
======================
上面兩種實現(xiàn)的執(zhí)行結(jié)果如下:
1: ====--Weather Report With Graphic Format--====
2: temperature = 23, humidity = 45
3: ====--Weather Report With Table Format--====
4: temperature = 23, humidity = 45
5: ====--Weather Report With Graphic Format--====
6: temperature = 23, humidity = 45
7: ====--Weather Report With Table Format--====
8: temperature = 67, humidity = 89
4. Push還是Pull?
對于上面的例子, Observer中的數(shù)據(jù)是從Subject中一次性全部更新的(temperature 和 humidity), 這種更新數(shù)據(jù)的方式便是push;然而如果WeatherData中的數(shù)據(jù)量非常大, 而有些Observer并不需要所有的數(shù)據(jù), 比如現(xiàn)在要新增兩個顯示方式,一個是只顯示溫度,而另一個則只顯示濕度, 這樣的話就沒有必要讓所有的Observer都得到所有的數(shù)據(jù). 最好的方式是Observer能根據(jù)自己的需要從Subject中去取得數(shù)據(jù),這種更新數(shù)據(jù)的方式便是Pull. Observer模式中Push和Pull兩種設計方法體現(xiàn)在具體的程序中就是Observer中的Update()接口參數(shù)不同, 對于Push模式, Update()接口的參數(shù)通常就是需要Push的那些數(shù)據(jù),比如這里的溫度和濕度; 對于Pull模式, Update()的參數(shù)是Subject的一個引用, 然后Subject提供一些數(shù)據(jù)接口,由Observer通過這些接口自己取得所需要的數(shù)據(jù).
5. 總結(jié):
1. Strategy 模式定義:
定義對象間的一種一對多的依賴關系,當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新.
2. 體現(xiàn)的設計原則:
- 將數(shù)據(jù)與現(xiàn)實分別封裝;
- 多使用組合,少使用繼承;
- 面向接口編程,而不面向?qū)崿F(xiàn)編程;
3. UML圖:
4. 要點:
- Strategy 基類需要定義出可供Client使用的一些算法接口;
- 可以隨時根據(jù)需要增加 Strategy 而不會影響到Client;
- Client 里面需要包含對 Strategy 的引用;
- Client 可以隨時更換 Strategy;
6. 理解:
- Observer模式是解決對象之間數(shù)據(jù)傳遞問題的一種模式;
- Observer的注冊可以由Subject執(zhí)行也可以由Observer自己執(zhí)行;
- 和Strategy模式的比較:
1) Observer模式中Observer 中定義了 Update()接口供 Subject調(diào)用; 而Strategy模式中,Strategy定義了AlgrithmInterface()供Client調(diào)用;
2) Observer模式中Subject和Observer是一對多的關系, 因此Subject是一次調(diào)用n個Observer的Update()接口;而Strategy模式中Client與Strategy之間是一對一的關系, Client 就是調(diào)用指定的那個Strategy的AlgrithmInterface();
3) 也正因為這種對應關系的不同, 在Observer模式中, Subject可以Register或者Remove某個Observer, 而Strategy模式中通常只是set某個Strategy
原文地址: http://blog.csdn.net/zhongjiekangping/article/details/6903017