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

- //這個(gè)例子中WeatherData就是Subject, 而WeatherView則是Observer,
- //這里WeatherView中沒(méi)有包含到WeatherData的引用,
- //因此這里是Subject用push的方法向Observer發(fā)送數(shù)據(jù);
- //并且注冊(cè)和反注冊(cè)O(shè)bserver的時(shí)候都是由Subject(WeatherData)執(zhí)行的
-
- #include <iostream>
- #include <vector>
- #include <algorithm>
-
- using namespace std;
-
- class WeatherData;
-
- class WeatherView
- {
- public:
- void Update(int temp, int hum)
- {
- temperature = temp;
- humidity = hum;
- };
- virtual void Display()
- {
- cout << "temperature = " << temperature << ", humidity = " << humidity << endl;
- }
-
- private:
-
- int temperature;
- int humidity;
- };
-
- class GraphicView: public WeatherView
- {
- public:
- void Display()
- {
- cout << "====--Weather Report With Graphic Format--===="<< endl;
- WeatherView::Display();
- }
- };
-
- class TableView: public WeatherView
- {
- public:
- void Display()
- {
- cout << "====--Weather Report With Table Format--===="<< endl;
- WeatherView::Display();
- }
- };
-
- class WeatherData
- {
- public:
- void SetWeahterData(int temp, int hum)
- {
- temperature = temp;
- humidity = hum;
- NotifyObservcer();
- }
-
- void RegisterObserver(WeatherView* obs)
- {
- obsList.push_back(obs);
- }
-
- void RemoveObserver(WeatherView* obs)
- {
- vector<WeatherView*>::iterator it;
- it = find(obsList.begin(), obsList.end(), obs);
- if (it != obsList.end())
- obsList.erase(it);
- }
-
- private:
- vector<WeatherView*> obsList;
- int temperature;
- int humidity;
- void NotifyObservcer()
- {
- vector<WeatherView*>::iterator it;
- for(it = obsList.begin(); it < obsList.end(); it++)
- {
- (*it)->Update(temperature, humidity);
- }
- }
- };
-
-
- int main()
- {
- WeatherData *wd = new WeatherData();
- GraphicView *gv = new GraphicView();
- TableView *tv = new TableView();
-
- wd->RegisterObserver(gv);
- wd->RegisterObserver(tv);
- wd->SetWeahterData(23,45);
- gv->Display();
- tv->Display();
-
- wd->RemoveObserver(gv);
- wd->SetWeahterData(67,89);
- gv->Display();
- tv->Display();
-
- return 0;
- }
2)用Pull的方式更新Observer數(shù)據(jù), Observer自己進(jìn)行注冊(cè):
- #ifndef WEATHERDATA_HPP_INCLUDED
- #define WEATHERDATA_HPP_INCLUDED
- #include <iostream>
- #include <vector>
-
- #include "WeatherView.hpp"
-
- class WeatherData
- {
- public:
- void SetWeahterData(int temp, int hum)
- {
- temperature = temp;
- humidity = hum;
- NotifyObservcer();
- }
-
- int GetTemperature()
- {
- return temperature;
- }
-
- int GetHumidty()
- {
- return humidity;
- }
-
- void RegisterObserver(WeatherView* obs);
- void RemoveObserver(WeatherView* obs);
-
- private:
- vector<WeatherView*> obsList;
- int temperature;
- int humidity;
- void NotifyObservcer();
- };
-
- #endif
- #ifndef WEATHERVIEW_HPP_INCLUDED
- #define WEATHERVIEW_HPP_INCLUDED
-
- #include <iostream>
- #include <vector>
- #include <algorithm>
-
-
- class WeatherData;
-
- using namespace std;
-
- class WeatherView
- {
- public:
- WeatherView(WeatherData* wd);
-
- void Update();
- void Register();
- void Unregister();
-
- virtual void Display()
- {
- cout << "temperature = " << temperature << ", humidity = " << humidity << endl;
- }
-
- private:
- WeatherData* wd;
- int temperature;
- int humidity;
- };
-
- class GraphicView: public WeatherView
- {
- public:
- GraphicView(WeatherData* wd);
- void Display()
- {
- cout << "====--Weather Report With Graphic Format--===="<< endl;
- WeatherView::Display();
- }
- };
-
- class TableView: public WeatherView
- {
- public:
- TableView(WeatherData* wd);
- void Display()
- {
- cout << "====--Weather Report With Table Format--===="<< endl;
- WeatherView::Display();
- }
- };
-
- #endif
- //這個(gè)例子中WeatherData就是Subject, 而WeatherView則是Observer,
- //這里WeatherView中有一個(gè)包含到WeatherData的指針,
- //因此這里是Observer用pull的方法主動(dòng)向Observer索取數(shù)據(jù);
- //并且注冊(cè)和反注冊(cè)都是Observer自己執(zhí)行的
- #include <iostream>
- #include <vector>
- #include <algorithm>
- #include "WeatherView.hpp"
- #include "WeatherData.hpp"
-
- void WeatherData::RegisterObserver(WeatherView* obs)
- {
- obsList.push_back(obs);
- }
-
- void WeatherData::RemoveObserver(WeatherView* obs)
- {
- vector<WeatherView*>::iterator it;
- it = find(obsList.begin(), obsList.end(), obs);
- if (it != obsList.end())
- obsList.erase(it);
- }
-
- void WeatherData::NotifyObservcer()
- {
- vector<WeatherView*>::iterator it;
- for(it = obsList.begin(); it < obsList.end(); it++)
- {
- (*it)->Update();
- }
- }
-
-
- WeatherView::WeatherView(WeatherData* pwd)
- {
- wd = pwd;
- }
-
- void WeatherView::Update()
- {
- temperature = wd->GetTemperature();
- humidity = wd->GetHumidty();
- };
-
- void WeatherView::Register()
- {
- wd->RegisterObserver(this);
- };
-
- void WeatherView::Unregister()
- {
- wd->RemoveObserver(this);
- };
-
- GraphicView::GraphicView(WeatherData* pwd) : WeatherView(pwd)
- {
-
- }
-
- TableView::TableView(WeatherData* pwd) : WeatherView(pwd)
- {
-
- }
- int main()
- {
- WeatherData *wd = new WeatherData();
- GraphicView *gv = new GraphicView(wd);
- gv->Register();
- TableView *tv = new TableView(wd);
- tv->Register();
-
- wd->SetWeahterData(23,45);
- gv->Display();
- tv->Display();
-
- gv->Unregister();
- wd->SetWeahterData(67,89);
- gv->Display();
- tv->Display();
-
- return 0;
- }
上面兩種實(shí)現(xiàn)的執(zhí)行結(jié)果如下:
- ====--Weather Report With Graphic Format--====
- temperature = 23, humidity = 45
- ====--Weather Report With Table Format--====
- temperature = 23, humidity = 45
- ====--Weather Report With Graphic Format--====
- temperature = 23, humidity = 45
- ====--Weather Report With Table Format--====
- temperature = 67, humidity = 89
4. Push還是Pull?
對(duì)于上面的例子, Observer中的數(shù)據(jù)是從Subject中一次性全部更新的(temperature 和 humidity), 這種更新數(shù)據(jù)的方式便是push;然而如果WeatherData中的數(shù)據(jù)量非常大, 而有些Observer并不需要所有的數(shù)據(jù), 比如現(xiàn)在要新增兩個(gè)顯示方式,一個(gè)是只顯示溫度,而另一個(gè)則只顯示濕度, 這樣的話(huà)就沒(méi)有必要讓所有的Observer都得到所有的數(shù)據(jù). 最好的方式是Observer能根據(jù)自己的需要從Subject中去取得數(shù)據(jù),這種更新數(shù)據(jù)的方式便是Pull. Observer模式中Push和Pull兩種設(shè)計(jì)方法體現(xiàn)在具體的程序中就是Observer中的Update()接口參數(shù)不同, 對(duì)于Push模式, Update()接口的參數(shù)通常就是需要Push的那些數(shù)據(jù),比如這里的溫度和濕度; 對(duì)于Pull模式, Update()的參數(shù)是Subject的一個(gè)引用, 然后Subject提供一些數(shù)據(jù)接口,由Observer通過(guò)這些接口自己取得所需要的數(shù)據(jù).
5. 總結(jié):
1. Strategy 模式定義:
定義對(duì)象間的一種一對(duì)多的依賴(lài)關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)于它的對(duì)象都得到通知并被自動(dòng)更新.
2. 體現(xiàn)的設(shè)計(jì)原則:
- 將數(shù)據(jù)與現(xiàn)實(shí)分別封裝;
- 多使用組合,少使用繼承;
- 面向接口編程,而不面向?qū)崿F(xiàn)編程;
3. UML圖:
4. 要點(diǎn):
- Strategy 基類(lèi)需要定義出可供Client使用的一些算法接口;
- 可以隨時(shí)根據(jù)需要增加 Strategy 而不會(huì)影響到Client;
- Client 里面需要包含對(duì) Strategy 的引用;
- Client 可以隨時(shí)更換 Strategy;
6. 理解:
- Observer模式是解決對(duì)象之間數(shù)據(jù)傳遞問(wèn)題的一種模式;
- Observer的注冊(cè)可以由Subject執(zhí)行也可以由Observer自己執(zhí)行;
- 和Strategy模式的比較:
1) Observer模式中Observer 中定義了 Update()接口供 Subject調(diào)用; 而Strategy模式中,Strategy定義了AlgrithmInterface()供Client調(diào)用;
2) Observer模式中Subject和Observer是一對(duì)多的關(guān)系, 因此Subject是一次調(diào)用n個(gè)Observer的Update()接口;而Strategy模式中Client與Strategy之間是一對(duì)一的關(guān)系, Client 就是調(diào)用指定的那個(gè)Strategy的AlgrithmInterface();
3) 也正因?yàn)檫@種對(duì)應(yīng)關(guān)系的不同, 在Observer模式中, Subject可以Register或者Remove某個(gè)Observer, 而Strategy模式中通常只是set某個(gè)Strategy
轉(zhuǎn)自:http://blog.csdn.net/minico/article/details/5471100
posted on 2012-10-30 17:16
老馬驛站 閱讀(390)
評(píng)論(0) 編輯 收藏 引用 所屬分類(lèi):
Design pattern