標籤:
概述:
近期中國股市起起伏伏,當然了起伏就用商機,小明發現商機後果斷想入市,買入了中國證券,他想在電腦client上,網頁上,手機上,iPad上都能夠查看到該證券的即時行情,這樣的情況下我們應該怎麼設計我們的軟體呢?我們能夠這樣:小明的全部client上都訂閱中國證券這個股票,僅僅要股票一有變化,全部的client都會被通知到而且被自己主動更新。
這就是我們的觀察者模式,她定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時, 全部依賴於它的對象都得到通知並被自己主動更新。
類圖與執行個體:
能夠看出,在這個觀察者模式的實現裡有以下這些角色:
抽象主題(Subject)角色:主題角色把全部對觀察考對象的引用儲存在一個聚集裡,每一個主題都能夠有不論什麼數量的觀察者。抽象主題提供一個介面,能夠添加和刪除觀察者對象,主題角色又叫做抽象被觀察者(Observable)角色,一般用一個抽象類別或者一個介面實現。
抽象觀察者(Observer)角色:為全部的詳細觀察者定義一個介面,在得到主題的通知時更新自己。這個介面叫做更新介面。抽象觀察者角色一般用一個抽象類別或者一個介面實現。在這個示意性的實現中,更新介面僅僅包括一個方法(即Update()方法),這種方法叫做更新方法。
詳細主題(ConcreteSubject)角色:將有關狀態存入詳細現察者對象;在詳細主題的內部狀態改變時,給全部登記過的觀察者發出通知。詳細主題角色又叫做詳細被觀察者角色(Concrete Observable)。詳細主題角色通經常使用一個詳細子類實現。
詳細觀察者(ConcreteObserver)角色:儲存與主題的狀態自恰的狀態。詳細現察者角色實現抽象觀察者角色所要求的更新介面,以便使本身的狀態與主題的狀態相協調。假設須要,詳細現察者角色能夠儲存一個指向詳細主題對象的引用。詳細觀察者角色通經常使用一個詳細子類實現。
從詳細主題角色指向抽象觀察者角色的合成關係,代表詳細主題對象能夠有隨意多個對抽象觀察者對象的引用。之所以使用抽象觀察者而不是詳細觀察者,意味著主題對象不須要知道引用了哪些ConcreteObserver類型,而僅僅知道抽象Observer類型。這就使得詳細主題對象能夠動態地維護一系列的對觀察者對象的引用,並在須要的時候調用每個觀察者共同擁有的Update()方法。這樣的做法叫做"針對抽象編程"。
這裡我們提供一個簡單化的執行個體:
#include <iostream>#include <vector>#include <string>using namespace std;class Secretary;// 看股票的同事類(觀察對象,觀察者)class StockObserver{public:StockObserver(string strName, Secretary* strSub){name = strName;sub = strSub;}void Update();private:string name;Secretary* sub;};// 秘書類(主題對象,通知者)class Secretary{public:string action;void Add(StockObserver ob) { observers.push_back(ob); }void Remove(int addIndex){if(addIndex >=0 && addIndex < observers.size())observers.erase(observers.begin() + addIndex);}void Notify(){vector<StockObserver>::iterator it;for (it=observers.begin(); it!=observers.end(); ++it){(*it).Update();}}private:vector<StockObserver> observers;};void StockObserver::Update(){cout << name << " : " << sub->action << ", begin to work" << endl;}int main(){// 建立通知者Secretary* p = new Secretary();// 觀察者StockObserver* s1 = new StockObserver("Lazy", p);StockObserver* s2 = new StockObserver("SnowFire", p);// 增加通知隊列p->Add(*s1);p->Add(*s2);// 事件p->action = "The boss is coming...";// 通知p->Notify();// 動態刪除p->Remove(0);p->Notify();return 0;}
適用性:
1.當一個抽象模型有兩個方面, 當中一個方面依賴於還有一方面。將這二者封裝在獨立的對象中以使它們能夠各自獨立地改變和複用。
2.當對一個對象的改變須要同一時候改變其他對象, 而不知道詳細有多少對象有待改變。
3.當一個對象必須通知其他對象,而它又不能假定其他對象是誰。換言之, 你不希望這些對象是緊密耦合的。
優缺點:
觀察者模式的效果有下面幾個長處:
1.觀察者模式在被觀察者和觀察者之間建立一個抽象的耦合。被觀察者角色所知道的僅僅是一個詳細現察者聚集,每個詳細現察者都符合一個抽象觀察者的介面。被觀察者並不認識不論什麼一個詳細觀察者,它僅僅知道它們都有一個共同的介面。因為被觀察者和觀察者沒有緊密地耦合在一起,因此它們能夠屬於不同的抽象化層次。
2.觀察者模式支援廣播通訊。被觀察者會向全部的登記過的觀察者發出通知。
觀察者模式有以下的一些缺點:
1.假設一個被觀察者對象有非常多直接和間接的觀察者的話,將全部的觀察者都通知到會花費非常多時間。
2.假設在被觀察者之間有循環相依性的話,被觀察者會觸發它們之間進行迴圈調用,導致系統崩潰。在使用觀察考模式時要特別注意這一點。
3.假設對觀察者的通知是通過另外的線程進行非同步投遞的話,系統必須保證投遞是以自恰的方式進行的。
4.儘管觀察者模式能夠隨時使觀察者知道所觀察的對象發生了變化,可是觀察者模式沒有對應的機制使觀察者知道所觀察的對象是怎麼發生變化的。
其它:1.在.NET中能夠利用Delegate與Event機制來實現觀察者模式。2.Java提供了Observer 和Observable來協助我們簡化實現觀察者模式。
LCL_data原創於CSDN.NET【http://blog.csdn.net/lcl_data/article/details/9208561】
其它設計模式請參考:我所理解的設計模式
我理解設計模式C++實現觀察者模式Observer Pattern