設計模式之觀察者模式(Observer)摘錄

來源:互聯網
上載者:User

標籤:style   class   blog   code   http   tar   

23種GOF設計模式一般分為三大類:建立型模式、結構型模式、行為模式。

建立型模式抽象了執行個體化過程,它們協助一個系統獨立於如何建立、組合和表示它的那些對象。一個類建立型模式使用繼承改變被執行個體化的類,而一個對象建立型模式將執行個體化委託給另一個對象。建立型模式有兩個不斷出現的主旋律。第一,它們都將關於該系統使用哪些具體的類的資訊封裝起來。第二,它們隱藏了這些類的執行個體是如何被建立和放在一起的。整個系統關於這些對象所知道的是由抽象類別所定義的介面。因此,建立型模式在什麼被建立,誰建立它,它是怎樣被建立的,以及何時建立這些方面給予了很大的靈活性。它們允許用結構和功能差別很大的“產品”對象配置一個系統。配置可以是靜態(即在編譯時間指定),也可以是動態(在運行時)。

結構型模式涉及到如何組合類別和對象以獲得更大的結構。結構型類模式採用繼承機制來組合介面或實現。結構型對象模式不是對介面和實現進行組合,而是描述了如何對一些對象進行組合,從而實現新功能的一些方法。因為可以在運行時刻改變對象組合關係,所以對象組合方式具有更大的靈活性,而這種機制用靜態類組合是不可能實現的。

行為模式涉及到演算法和對象間職責的分配。行為模式不僅描述對象或類的模式,還描述它們之間的通訊模式。這些模式刻畫了在運行時難以跟蹤的複雜的控制流程。它們將使用者的注意力從控制流程轉移到對象間的連絡方式上來。行為類模式使用繼承機制在類間指派行為。行為對象模式使用對象複合而不是繼承。一些行為對象模式描述了一組對等的對象怎樣相互協作以完成其中任一個對象都無法單獨完成的任務。

建立型模式包括:1、FactoryMethod(Factory 方法模式);2、Abstract Factory(抽象原廠模式);3、Singleton(單例模式);4、Builder(建造者模式、產生器模式);5、Prototype(原型模式).

結構型模式包括:6、Bridge(橋接模式);7、Adapter(適配器模式);8、Decorator(裝飾模式);9、Composite(組合模式);10、Flyweight(享元模式);11、Facade(面板模式);12、Proxy(代理模式).

行為模式包括:13、TemplateMethod(模板方法模式);14、Strategy(策略模式);15、State(狀態模式);16、Observer(觀察者模式);17、Memento(備忘錄模式);18、Mediator(中介者模式);19、Command(命令模式);20、Visitor(訪問者模式);21、Chain of Responsibility(責任鏈模式);22、Iterator(迭代器模式);23、Interpreter(解譯器模式).

Factory Method:定義一個用於建立對象的介面,讓子類決定將哪一個類執行個體化。Factory Method使一個類的執行個體化延遲到其子類。

Abstract Factory:提供一個建立一系列相關或相互依賴對象的介面,而無需指定他們具體的類。

Singleton:保證一個類僅有一個執行個體,並提供一個訪問它的全域訪問點。

Builder:將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。

Prototype:用原型執行個體指定建立對象的種類,並且通過拷貝這個原型來建立新的對象。

Bridge:將抽象部分與它的實現部分分離,使它們都可以獨立地變化。

Adapter:將一個類的介面轉換成客戶希望的另外一個介面。Adapter模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。

Decorator:動態地給一個對象添加一些額外的職責。就擴充功能而言, Decorator模式比產生子類方式更為靈活。

Composite:將對象組合成樹形結構以表示“部分-整體”的階層。Composite使得客戶對單個對象和綜合物件的使用具有一致性。

Flyweight:運用共用技術有效地支援大量細粒度的對象。

Facade:為子系統中的一組介面提供一個一致的介面, Facade模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。

Proxy:為其他對象提供一個代理以控制對這個對象的訪問。

Template Method:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。

Strategy:定義一系列的演算法,把它們一個個封裝起來, 並且使它們可相互替換。本模式使得演算法的變化可獨立於使用它的客戶。

State:允許一個對象在其內部狀態改變時改變它的行為。對象看起來似乎修改了它所屬的類。

Observer:定義對象間的一種一對多的依賴關係,以便當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並自動重新整理。

Memento:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外儲存這個狀態。這樣以後就可將該對象恢複到儲存的狀態。

Mediator:用一個中介對象來封裝一系列的對象互動。中介者使各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動。

Command:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支援可取消的操作。

Visitor:表示一個作用於某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。

Chain of Responsibility:為解除請求的寄件者和接收者之間耦合,而使多個對象都有機會處理這個請求。將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理它。

Iterator:提供一種方法順序訪問一個彙總對象中各個元素, 而又不需暴露該對象的內部表示。

Interpreter:給定一個語言, 定義它的文法的一種表示,並定義一個解譯器, 該解譯器使用該表示來解釋語言中的句子。

         Observer:(1)、意圖:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。

         (2)、適用性:A、當一個抽象模型有兩個方面,其中一個方面依賴於另一方面。將這兩者封裝在獨立的對象中以使它們可以各自獨立地改變和複用。B、當對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變。C、當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之,你不希望這些對象是緊密耦合的。

         (3)、優缺點:A、目標和觀察者間的抽象耦合:一個目標所知道的僅僅是它有一系列觀察者,每個都符合抽象的Observer類的簡單介面。目標不知道任何一個觀察者屬於哪一個具體的類。這樣目標和觀察者之間的耦合是抽象的和最小的。因為目標和觀察者不是緊密耦合的,它們可以屬於一個系統中的不同抽象層次。一個處於較低層次的目標對象可與一個處於較高層次的觀察者通訊並通知它,這樣就保持了系統層次的完整。如果目標和觀察者混在一塊,那麼得到的對象要麼橫貫兩個層次(違反了層次性),要麼必須放在這兩層的某一層中(這可能會損害層次抽象)。B、支援廣播通訊:不像通常的請求,目標發送的通知不需指定它的接收者。通知被自動廣播給所有已向該目標對象登記的有關對象。目標對象並不關心到底有多少對象對自己感興趣;它唯一的責任就是通知它的各觀察者。這給了你在任何時刻增加和刪除觀察者的自由。處理還是忽略一個通知取決於觀察者。C、意外的更新:因為一個觀察者並不知道其它觀察者的存在,它可能對改變目標的最終代價一無所知。在目標上一個看似無害的操作可能會引起一系列對觀察者以及依賴於這些觀察者的那些對象的更新。此外,如果依賴準則的定義或維護不當,常常會引起錯誤的更新,這種錯誤通常很難捕捉。簡單的更新協議不提供具體細節說明目標中什麼被改變了,這就使得上述問題更加嚴重。如果沒有其他協議協助觀察者發現什麼發生了改變,它們可能會被迫儘力減少改變。

         (4)、相關模式:A、Mediator:通過封裝複雜的更新語義,ChangeManager(當目標和觀察者間的依賴關係特別複雜時,可能需要一個維護這些關係的對象。我們稱這樣的對象為更改管理器。它的目的是盡量減少觀察者反映其目標的狀態變化所需的工作量) 充當目標和觀察者之間的中介者。B、Singleton:ChangeManager可使用Singleton模式來保證它是唯一的並且是可全域訪問的。

         (5)、觀察者模式:定義了一種一對多的關係,讓多個觀察對象同時監聽一個主題對象,主題對象狀態發生變化時,會通知所有的觀察者,使它們能夠更新自己。

         (6)、Observer模式要解決的問題為:建立一個一(Subject)對多(Observer)的依賴關係,並且做到當“一”變化的時候,依賴這個”一”的多也能夠同步改變。最常見的一個例子就是:對同一組資料進行統計分析的時候,我們希望能夠提供多種形式的表示(例如以表格進行統計顯示、柱狀圖統計顯示、百分比統計顯示等)。這些表示都依賴於同一組資料,我們當然需要當資料改變的時候,所有的統計的顯示都能夠同時改變。Observer模式就是解決了這一關問題。

範例程式碼1:

#include <string>#include <iostream>#include <vector>using namespace std;class Secretary;//看股票的同事類(觀察對象,觀察者)class StockObserver{private:string name;Secretary* sub;public:StockObserver(string strname, Secretary* strsub){name = strname;sub = strsub;}void Update();};//秘書類(主題對象,通知者)class Secretary{private:vector<StockObserver> observers;public:string action;void Add(StockObserver ob){observers.push_back(ob);}void Notify(){vector<StockObserver>::iterator p = observers.begin();while (p != observers.end()){(*p).Update();p ++;}}};void StockObserver::Update(){cout<<name<<":"<<sub->action<<",不要玩股票了,要開始工作了"<<endl;}//用戶端int main(){Secretary* p = new Secretary();//建立通知者//觀察者StockObserver* s1 = new StockObserver("小李", p);StockObserver* s2 = new StockObserver("小趙", p);//加入通知隊列p->Add(*s1);p->Add(*s2);//事件p->action = "老闆來了";//通知p->Notify();/*result小李:老闆來了,不要玩股票了,要開始工作了小趙:老闆來了,不要玩股票了,要開始工作了*/return 0;}

範例程式碼2:

#include <string>#include <iostream>#include <vector>using namespace std;class SecretaryBase;//抽象觀察者class CObserverBase{protected:string name;SecretaryBase* sub;public:CObserverBase(string strname, SecretaryBase* strsub){name = strname;sub = strsub;}virtual void Update() = 0;};//具體的觀察者,看股票的class StockObserver : public CObserverBase{public:StockObserver(string strname, SecretaryBase* strsub) : CObserverBase(strname, strsub){}virtual void Update();};//具體觀察者,看NBA的class NBAObserver : public CObserverBase{public:NBAObserver(string strname, SecretaryBase* strsub) : CObserverBase(strname, strsub){}virtual void Update();};//抽象通知者class SecretaryBase{public:string action;vector<CObserverBase*> observers;public:virtual void Attach(CObserverBase* observer) = 0;virtual void Notify() = 0;};//具體通知者class Secretary : public SecretaryBase{public:void Attach(CObserverBase* ob){observers.push_back(ob);}void Notify(){vector<CObserverBase*>::iterator p = observers.begin();while (p != observers.end()){(*p)->Update();p ++;}}};void StockObserver::Update(){cout<<name<<":"<<sub->action<<"不要玩股票了,要開始工作了"<<endl;}void NBAObserver::Update(){cout<<name<<":"<<sub->action<<"不要看NBA了,老闆來了"<<endl;}//用戶端int main(){SecretaryBase* p = new Secretary();//建立觀察者//被觀察的對象CObserverBase* s1 = new NBAObserver("小李", p);CObserverBase* s2 = new StockObserver("小趙", p);//加入觀察隊列p->Attach(s1);p->Attach(s2);//事件p->action = "老闆來了";//通知p->Notify();/*result小李:老闆來了不要看NBA了,老闆來了小趙:老闆來了不要玩股票了,要開始工作了*/return 0;}

範例程式碼3:

Subject.h:

#ifndef _SUBJECT_H_#define _SUBJECT_H_#include <list>#include <string>using namespace std;typedef string State;class Observer;class Subject{public:virtual ~Subject();virtual void Attach(Observer* obv);virtual void Detach(Observer* obv);virtual void Notify();virtual void SetState(const State& st) = 0;virtual State GetState() = 0;protected:Subject();private:list<Observer*>* _obvs;};class ConcreteSubject : public Subject{public:ConcreteSubject();~ConcreteSubject();State GetState();void SetState(const State& st);protected:private:State _st;};#endif//~_SUBJECT_H_

Subject.cpp:

#include "Subject.h"#include "Observer.h"#include <iostream>#include <list>using namespace std;typedef string state;Subject::Subject(){//在模板的使用之前一定要new,建立_obvs = new list<Observer*>;}Subject::~Subject(){}void Subject::Attach(Observer* obv){_obvs->push_front(obv);}void Subject::Detach(Observer* obv){if (obv != NULL)_obvs->remove(obv);}void Subject::Notify(){list<Observer*>::iterator it;it = _obvs->begin();for (; it != _obvs->end(); it ++) //關於模板和iterator的用法(*it)->Update(this);}ConcreteSubject::ConcreteSubject(){_st = ‘\0‘;}ConcreteSubject::~ConcreteSubject(){}State ConcreteSubject::GetState(){return _st;}void ConcreteSubject::SetState(const State& st){_st = st;}

Observer.h:

#ifndef _OBSERVER_H_#define _OBSERVER_H_#include "Subject.h"#include <string>using namespace std;typedef string State;class Observer{public:virtual ~Observer();virtual void Update(Subject* sub) = 0;virtual void PrintInfo() = 0;protected:Observer();State _st;private:};class ConcreteObserverA : public Observer{public:virtual Subject* GetSubject();ConcreteObserverA(Subject* sub);virtual ~ConcreteObserverA();//傳入Subject作為參數,這樣可以讓一個View屬於多個的Subjectvoid Update(Subject* sub);void PrintInfo();protected:private:Subject* _sub;};class ConcreteObserverB : public Observer{public:virtual Subject* GetSubject();ConcreteObserverB(Subject* sub);virtual ~ConcreteObserverB();//傳入Subject作為參數,這樣可以讓一個View屬於多個的Subjectvoid Update(Subject* sub);void PrintInfo();protected:private:Subject* _sub;};#endif//~_OBSERVER_H_

Observer.cpp:

#include "Observer.h"#include "Subject.h"#include <iostream>#include <string>using namespace std;Observer::Observer(){_st = ‘\0‘;}Observer::~Observer(){}ConcreteObserverA::ConcreteObserverA(Subject* sub){_sub = sub;_sub->Attach(this);}ConcreteObserverA::~ConcreteObserverA(){_sub->Detach(this);if (_sub != 0)delete _sub;}Subject* ConcreteObserverA::GetSubject(){return _sub;}void ConcreteObserverA::PrintInfo(){cout<<"ConcreteObserverA observer ..."<<_sub->GetState()<<endl;}void ConcreteObserverA::Update(Subject* sub){_st = sub->GetState();PrintInfo();}ConcreteObserverB::ConcreteObserverB(Subject* sub){_sub = sub;_sub->Attach(this);}ConcreteObserverB::~ConcreteObserverB(){_sub->Detach(this);if (_sub != 0)delete _sub;}Subject* ConcreteObserverB::GetSubject(){return _sub;}void ConcreteObserverB::PrintInfo(){cout<<"ConcreteObserverB observer ..."<<_sub->GetState()<<endl;}void ConcreteObserverB::Update(Subject* sub){_st = sub->GetState();PrintInfo();}

main.cpp:

#include "Subject.h"#include "Observer.h"#include <iostream>using namespace std;int main(){ConcreteSubject* sub = new ConcreteSubject();Observer* o1 = new ConcreteObserverA(sub);Observer* o2 = new ConcreteObserverB(sub);sub->SetState("old");sub->Notify();sub->SetState("new");//也可以由Observer調用sub->Notify();/*resultConcreteObserverB observer ...oldConcreteObserverA observer ...oldConcreteObserverB observer ...newConcreteObserverA observer ...new*/return 0;}

觀察者模式結構圖:


參考文獻:

1、《大話設計模式C++》

2、《設計模式精解----GoF23種設計模式解析》

3、《設計模式----可複用物件導向軟體的基礎》

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.