設計模式(16) 觀察者模式(OBSERVER)C++實現


意圖:

定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。

動機:

將一個系統設計成一系列相互協作的類有一個常見的副作用:需要維護相關對象之間的一致性。

觀察者模式定義一種交互,即發布-訂閱:

  • 一個對象當自身狀態發生改變時,會發出通知,但是並不知道誰是他的接收者,但每個接收者都會接收到通知,這些接受者稱為觀察者。
  • 作為對通知的響應,每個觀察者都將查詢目標狀態,然后改變自身的狀態以和目標狀態進行同步。

使用場景:

  • 使對象封裝為獨立的改變和使用;
  • 一個對象改變同時需要改變其它對象,而不知道具體有多少對象需要改變;
  • 不希望對象是緊耦合的。

結構:

clipboard

參與者:

Subject:目標,知道它的觀察者,提供注冊和刪除觀察者對象的接口

Observer:觀察者,為那些在目標發生改變時需獲得通知的對象定義一個更新接口

ConcreteSubject:具體目標,存儲對象狀態,狀態改變時,向各個觀察者發出通知

ConcreteObserver:具體觀察者,維護一個指向ConcreteSubject對象的引用,存儲有關狀態,實現更新接口update,使自身狀態與目標的狀態保持一致

優缺點:

1 目標和觀察者之間松耦合

2 支持廣播通信:Subject發送的通知不需要指定它的接受者。通知被自動廣播給所有已向該目標對象登記的有關對象。

3 意外的更新:看似無害的操作可能會引起觀察者錯誤的更新。


示例代碼:

  1 /*
  2  * 觀察者模式
  3  * 情景:高數課,ABCD四位同學,A是好學生,去上課,B在寢室睡覺,C在網吧打游戲,D在學校外陪女友逛街
  4  * 他們約定,如果要點名了,A在QQ群里吼一聲,他們立刻趕到教室去。
  5  * 采用觀察者模式實現這個情景的應用。
  6  */
  7 
  8 #include <iostream>
  9 #include <string>
 10 #include <list>
 11 
 12 class Observer;
 13 
 14 class Subject{
 15 public:
 16     virtual ~Subject() {};
 17     virtual void registerObsvr(Observer* obsvr) = 0;
 18     virtual void removeObsvr(Observer* obsvr) = 0;
 19     virtual void notifyObsvrs(const std::string &msg) = 0;
 20 };
 21 class Observer {
 22 public:
 23     virtual ~Observer() {};
 24     virtual void Update(const std::string &msg)= 0;
 25     virtual std::string getName() = 0;
 26 protected:
 27     Observer(){};
 28 };
 29 
 30 // -------------------------------------------------
 31 class QQGroup : public Subject {
 32 public:
 33     QQGroup() { _observers = new std::list<Observer*>(); }
 34     void registerObsvr(Observer* obsvr);
 35     void removeObsvr(Observer* obsvr);
 36     void notifyObsvrs(const std::string &msg);
 37 private:
 38     std::list<Observer*> *_observers;
 39 };
 40 
 41 void QQGroup::registerObsvr(Observer* obsvr) {
 42     _observers->push_back(obsvr);
 43 }
 44 
 45 void QQGroup::removeObsvr(Observer* obsvr) {
 46     if (_observers->size() > 0)
 47         _observers->remove(obsvr);
 48 }
 49 void QQGroup::notifyObsvrs( const std::string &msg) {
 50     std::cout << "群消息:" << msg << std::endl;
 51     std::list<Observer*>::iterator iter
 52         = _observers->begin();
 53     for ( ;iter != _observers->end(); iter++ ) {
 54         (*iter)->Update(msg);
 55     }
 56 }
 57 
 58 // ------------------------------------------------
 59 class RoomMate : public Observer {
 60 public:
 61     RoomMate(std::string name, std::string now ,std::string action)
 62     {
 63         _name = name;
 64         _action = action;
 65         _now = now;
 66     };
 67     void Update( const std::string &msg);
 68     std::string getName();
 69 private:
 70     std::string _name;
 71     std::string _action;
 72     std::string _now;
 73 };
 74 
 75 std::string RoomMate::getName() {
 76     return _name;
 77 }
 78 
 79 void RoomMate::Update(const std::string &msg) {
 80     std::cout<< "This is " << _name << std::endl;
 81     if ( msg == "點名了" )
 82         std::cout << "Action: " << _action
 83         << std::endl << std::endl;
 84     else
 85         std::cout << "Go on:" << _now
 86         << std::endl << std::endl ;
 87 }
 88 
 89 //測試代碼
 90 int main()
 91 {
 92     RoomMate* B = new RoomMate("B",
 93         "sleeping",
 94         "get dressed and run to classroom");
 95     RoomMate* C = new RoomMate("C",
 96         "playing games",
 97         "pay the fee and run to classroom");
 98     RoomMate* D = new RoomMate("D",
 99         "shopping with girl friend",
100         "go back to school and be worried about girl friend's angry");
101 
102     QQGroup* qqgroup = new QQGroup();
103     qqgroup->registerObsvr(B);
104     qqgroup->registerObsvr(C);
105     qqgroup->registerObsvr(D);
106 
107     qqgroup->notifyObsvrs("目前沒點名");
108     qqgroup->notifyObsvrs("點名了");
109 
110     system("Pause");
111     return 0;
112 }

 

運行截圖

clipboard[1]

 

相關模式:

中介者模式:通過封裝負責的更新條件來實現對象間的交互

觀察者模式:使用廣播-接收模式實現對象間的交互,不需要維護一個復雜的中介者類

 

 

參考資料:

《設計模式:可復用面向對象軟件的基礎》

設計模式----觀察者模式(C++)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM