程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 設計模式之觀察者模式與其C++通用實現(上)

設計模式之觀察者模式與其C++通用實現(上)

編輯:關於C++

觀察者模式

意圖:

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

結構:

優點:

目標(Subject)與觀察者(Observer)間抽象耦合

支持廣播通信/通知

缺點:

會帶來意外更新問題

示例:

考慮這樣一個例子:想知道公司最新的MM情報嗎?加入我們MM情報郵件組吧。您只需要向我們發送一封訂閱郵件即可,我們會把最新的MM情報以電子郵件形式通知您。

現在我們來一步一步實現。很明顯,示例中關心MM情況的人物即為訂閱者,我們以Subscriber表示這一類人。在定義Subscriber之前我們先定義一個MMStatus枚舉,用以表示MM狀態:

1.enum MMStatus {Dining, Sleeping, Working};

這裡定義了三個常量用以簡單地模擬MM所處的狀態。現在我們可以定義Subscriber類了:

1.struct Subscriber
2.{
3. virtual void action(MMStatus status) = 0;
4. virtual ~Subscriber() {}
5.};

有經驗的讀者知道,這樣定義Subscriber表明它是個基類,也是個抽象類,或者稱之為接口(java中就有 interface關鍵字)。之所以這樣設計,是因為可能存在很多種類型的訂閱者(Subscriber接口的子類),每種訂閱者對MM的同一種狀態可能會有不同的處理方式。這裡把多種類型的訂閱者抽象出相同的接口方法,也就是Subscriber定義的第3行。第4行雖然只是個空定義,但這是不可缺少的,防止在用基類指針指向子類而delete基類指針時子類的析構行為能正確調用。我們繼續定義我們的目標類。沒錯,就是MM情報組,我們以 MMIntelligenceAgent類表示。

1.class MMInteligenceAgent
2.{
3.public:
4. void subscribe(Subscriber &subscriber);
5. void desubscribe(Subscriber &subscriber);
6.private:
7. void notifyAll(MMStatus status);
8.private:
9. std::list<Subscriber*> subscribers_;
10.};

MMInteligenceAgent類有兩個公有方法(4、5行),分別用以增加和移除一個訂閱者。訂閱者可能有多個,我們選擇以鏈表存儲之(9行)。當MM狀態變更後,借助notifyAll方法,鏈表中的所有訂閱者都會得到通知。

目標類的實現很簡單:

1.void MMInteligenceAgent::subscribe(Subscriber &subscriber)
2.{
3. subscribers_.push_back(&subscriber);
4.}
5.
6.void MMInteligenceAgent::desubscribe(Subscriber &subscriber)
7.{
8. subscribers_.erase(
9. std::remove(subscribers_.begin(), subscribers_.end(), &subscriber),
10. subscribers_.end());
11.}
12.void MMInteligenceAgent::notifyAll(MMStatus status)
13.{
14. for (list<Subscriber*>::iterator it = subscribers_.begin();
15. it != subscribers_.end(); ++it) {
16. (*it)->action(status);
17. }
18.}

主要的基類及方法都寫好了,接下來我們示例個具體Subscriber類:偷竊者。偷竊者一般在偷盜目標熟睡時比較容易下手,於是偷竊者可使用MM情報組提供的服務,以便知道MM何時在睡覺:

1.struct Larcener : public Subscriber
2.{
3. virtual void action(MMStatus status)
4. {
5. if (status == Sleeping) {
6. // steal something ...
7. }
8. }
9.};

為了使代碼更完整,我們可以為MMInteligenceAgent增加一個對MM的跟蹤方法,當發現MM狀態改變時發出通知。

1.void MMInteligenceAgent::trace()
2.{
3. ...
4. MMStatus status = ...;
5. notifyAll(status);
6.}

最後以一個調用示例作為此篇的結束:

1.int main()
2.{
3. ...
4. Larcener l;
5. MMInteligenceAgent mia;
6. mia.subscribe(l);
7. mia.trace();
8. ...
9. mia.desubscribe(l);
10. ...
11.}

<未完,待續>

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved