標籤:style blog http color 使用 strong
觀察者模式又叫發布-訂閱(Publish/SubScribe)模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一主題對象。這個主題對象在狀態發生變化時,會通知所有觀察者對象,使他們能夠自動更新自己。
#include <iostream>#include <list>using namespace std;/*Observer類,抽象觀察者,為所有的具體觀察者定義一個介面,在得到主題的通知時更新自己。這個介面叫做更新介面。抽象觀察者一般用一個抽象類別或者一個介面實現。更新介面通常包含一個Updata()方法,叫做更新方法。*/class Observer{public: virtual void Update()=0;};/*Subject類,可翻譯為主題或抽象通知者,一般用一個抽象類別或者一個介面實現。他把所有對觀察者對象的引用儲存在一個聚集裡,每個主題都可以有任何數量的觀察者。抽象主題提供一個介面,可以增加和刪除觀察者對象*/class Subject{private: list<Observer *> observers; string subjectState;public: //增加觀察者 void Attach(Observer *observer) { observers.push_back(observer); } //移除觀察者 void Detach(Observer *observer) { observers.remove(observer); } //通知 void Notify() { list<Observer*>::iterator iter=observers.begin(); for(;iter!=observers.end();iter++) { (*iter)->Update(); } } /*virtual void setStatus(string s) { this->subjectState=s; } virtual string GetState() { return this->subjectState; }*/};/*ConcreteSubject類,叫做具體主題或者具體通知者,將有關狀態存入具體觀察著對象;在具體主題的內部狀態變化時,給所有登記過觀察者發出通知。具體主題角色通常用一個具體子類實現*/class ConcreteSubject:public Subject{private: string subjectState;public: void setStatus(string value) { this->subjectState=value; } string GetState() { return this->subjectState; }};/*ConcreteObserver類,具體觀察者,實現抽象觀察者角色所要求的更新介面,以便使本身的狀態與主題的狀態相協調。具體觀察者角色可以儲存一個指向具體主題對象的引用。具體觀察者角色通常用一個具體子類實現*/class ConcreteObserver:public Observer{private: string m_name; string observerState; ConcreteSubject *sub;public: ConcreteObserver(ConcreteSubject *subj,string name) { this->sub=subj; this->m_name=name; } void Update() { this->observerState=sub->GetState(); cout << "觀察者" << this->m_name << "的新狀態是" << this->observerState << endl; }};int main(){ ConcreteSubject *s = new ConcreteSubject(); s->Attach(new ConcreteObserver(s,"X")); s->Attach(new ConcreteObserver(s,"Y")); s->Attach(new ConcreteObserver(s,"Z")); s->setStatus("ABC"); s->Notify(); return 0;}
觀察模式的動機是將一個系統分割成一系列相互協作的類有一個很不好的副作用,那就是需要維護相關對象間的一致性。我們不希望為了威化一致性而使各類緊密耦合,這樣會給維護、擴充和重用都帶來不便。而觀察者模式的關鍵對象是主題Subject和觀察者Observer,一個Subject可以有任意數目的依賴它的Observer,一旦Subject的狀態發生了改變,所有的Observer都可以通知到。Subject發出通知時並不需要知道誰是它的觀察者,也就是說,具體觀察者是誰,它根本不需要知道。而任何一個具體觀察者不知道也不需要知道其他觀察者模式的存在。
當一個對象的改變需要同時改變其他對象,而且他不知道具體有多少對象有待改變時,應該考慮使用觀察者模式。當一個抽象模型有兩方面,其中一個方面依賴於另一方面,這時用觀察者模式可以將這兩者封裝在獨立的對象中使他們各自獨立地改變和複用。
總的來說,觀察者模式所做的工作其實就是在解除耦合。讓耦合的雙方都依賴於抽象,而不是依賴於具體。從而使得各自的變化都不會影響另一邊的變化。
舉個例子,下面是代碼結構圖:
#include <iostream>#include <list>using namespace std;class Subject;class Observer{public: virtual void Update()=0;};class Subject{private: string m_status;public: virtual void Attach(Observer *obser)=0; virtual void Detach(Observer *obser)=0; virtual void Notify()=0; virtual void SetStatus(string st)=0; virtual string GetStatus()=0;};class Boss:public Subject{private: list<Observer *> observer; string action;public: void Attach(Observer *obser) { observer.push_back(obser); } void Detach(Observer *obser) { observer.remove(obser); } void Notify() { list<Observer*>::iterator iter=observer.begin(); for(;iter!=observer.end();iter++) { (*iter)->Update(); } } void SetStatus(string stat) { this->action=stat; } string GetStatus() { return this->action; }};class Secretary:public Subject{private: list<Observer *> observer; string action;public: void Attach(Observer *obser) { observer.push_back(obser); } void Detach(Observer *obser) { observer.remove(obser); } void Notify() { list<Observer*>::iterator iter=observer.begin(); for(;iter!=observer.end();iter++) { (*iter)->Update(); } } void SetStatus(string stat) { this->action=stat; } string GetStatus() { return this->action; }};class StockObserver:public Observer{private: string m_name; Subject *subject; string m_status;public: StockObserver(string name,Subject *sub) { this->m_name=name; this->subject=sub; } void Update() { this->m_status=subject->GetStatus(); cout << this->m_status << this->m_name << "關閉股票行情,繼續工作!" << endl; }};class NBAObserver:public Observer{private: string m_name; Subject *subject; string m_status;public: NBAObserver(string name,Subject *sub) { this->m_name=name; this->subject=sub; } void Update() { this->m_status=subject->GetStatus(); cout << this->m_status << this->m_name << "關閉NBA直播,繼續工作!" << endl; }};int main(){ Boss *huhansan=new Boss(); StockObserver *tongshi1=new StockObserver("Tom",huhansan); NBAObserver *tongshi2=new NBAObserver("Jack",huhansan); huhansan->Attach(tongshi1); huhansan->Attach(tongshi2); huhansan->Detach(tongshi1); huhansan->SetStatus("我胡漢三回來了!"); huhansan->Notify(); return 0;}