设计模式(c++)笔记之十六(Observer模式)

来源:互联网 发布:南开大学网络教学平台 编辑:程序博客网 时间:2024/06/05 06:36

一、描述


      观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

      一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其它的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作(Collaboration)。


Observer 模式典型的结构图为: 



图 2-1:Observer Pattern 结构图


      这里的目标 Subject 提供依赖于它的观察者 Observer 的注册(Attach)和注销(Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作(Notify)。观察者 Observer 则提供一个 Update 操作,注意这里的 Observer 的 Update 操作并不在 Observer 改变了 Subject 目标状态的时候就对自己进行更新,这个更新操作要延迟到 Subject 对象发出 Notify 通知所有Observer 进行修改(调用 Update)。 


二、实例:


描述:

      《孙子兵法》有云:“知彼知己,百战不殆;不知彼而知己,一胜一负;不知彼,不知己,每战必殆”,那怎么才能知己知彼呢?知己是很容易的,自己的军队嘛,很容易知道,那怎么知彼呢?安插间谍是很好的一个办法,我们今天就来讲一个间谍的故事。

      韩非子大家都应该记得吧,法家的代表人物,主张建立法制社会,实施重罚制度,真是非常有远见呀,看看现在社会在呼吁什么,建立法制化的社会,在 2000 多年前就已经提出了。大家可能还不知道,法家还有一个非常重要的代表人物,李斯,对,就是李斯,秦国的丞相,最终被残忍的车裂的那位,李斯和韩非子都是荀子的学生,李斯是师兄,韩非子是师弟,若干年后,李斯成为最强诸侯秦国的上尉,致力于统一全国,于是安插了间谍到各个国家的重要人物的身边,以获取必要的信息,韩非子作为韩国的重量级人物,身边自然没少间谍了,韩非子早饭吃的什么,中午放了几个 P,晚上在做什么娱乐,李斯都了如指掌,那可是相隔千里!怎么做到的呢?间谍呀! 好,我们先通过程序把这个过程展现一下,看看李斯是怎么监控韩非子,先看类图: 




我的工程目录:


            


注释:

main(),主程序

IObservable,被观察者接口

CHanFeiZiObservable,被观察者韩非子

IObserver,观察者接口

CLiSiObserver,观察者李斯

CZhouSiObserver观察者周斯

说明:将观察者聚集到被观察者韩非子身边,韩非子的每一个举动都会通知给观察者,如李斯或周斯。

注意:最多允许一个对象既是观察者也是被观察者。就像数据库中的触发器一样,成为一个复杂的链就很难维护了。观察者类似于委托的处理方式。


观察者接口:IObserver

IObserver.h

[cpp] view plain copy
  1. #ifndef __Observer__IObserver__  
  2. #define __Observer__IObserver__  
  3.   
  4. #include <iostream>  
  5. #include <string>  
  6. using std::string;  
  7. class IObserver  
  8. {     
  9. public:  
  10.     IObserver(string _name){this->m_name = _name;}  
  11.     virtual ~IObserver(void){}  
  12.       
  13.     //一发现别人有动静,自己也要行动起来  
  14.     virtual void Update(string context) = 0;  
  15.       
  16.     //为c++单独增加的函数,用于删除时查找观察者。  
  17.     virtual string GetName() = 0;  
  18.       
  19. protected:  
  20.     string m_name;  
  21. };  
  22.   
  23.   
  24. #endif /* defined(__Observer__IObserver__) */  

观察者李斯:LiSiObserver类

LiSiObserver.h

[cpp] view plain copy
  1. #ifndef __Observer__LiSiObserver__  
  2. #define __Observer__LiSiObserver__  
  3.   
  4. #include <iostream>  
  5. #include "IObserver.h"  
  6.   
  7. class CLiSiObserver:public IObserver  
  8. {  
  9. public:  
  10.     CLiSiObserver(void);  
  11.     ~CLiSiObserver(void);  
  12.     //一发现别人有动静,自己也要行动起来  
  13.     void Update(string context);  
  14.     string GetName();  
  15. private:  
  16.     void ReportToQinShiHuang(string report);  
  17. };  
  18.   
  19.   
  20. #endif /* defined(__Observer__LiSiObserver__) */  
LiSiObserver.cpp

[cpp] view plain copy
  1. #include "LiSiObserver.h"  
  2. using std::cout;  
  3. using std::endl;  
  4. using std::string;  
  5.   
  6. CLiSiObserver::CLiSiObserver(void):IObserver("李斯")  
  7. {  
  8. }  
  9.   
  10. CLiSiObserver::~CLiSiObserver(void)  
  11. {  
  12.       
  13. }  
  14.   
  15. //首先李斯是个观察者,一旦韩非子有活动,他就知道,他就要向老板汇报  
  16. void CLiSiObserver::Update(string context)  
  17. {  
  18.     cout << "李斯:观察到韩非子活动,开始向老板汇报了..." << endl;  
  19.     this->ReportToQinShiHuang(context);  
  20.     cout << "李斯:汇报完毕,秦老板赏给他两个萝卜吃吃..." << endl;  
  21. }  
  22.   
  23. //汇报给秦始皇  
  24. void CLiSiObserver::ReportToQinShiHuang(string report)  
  25. {  
  26.     cout << "李斯:报告,秦老板!韩非子有活动了--->" << report.c_str() << endl;  
  27. }  
  28.   
  29. string CLiSiObserver::GetName()  
  30. {  
  31.     return m_name;  
  32. }  

观察者周斯:ZhouSiObserver类

ZhouSiObserver.h

[cpp] view plain copy
  1. #ifndef __Observer__ZhouSiObserver__  
  2. #define __Observer__ZhouSiObserver__  
  3.   
  4. #include <iostream>  
  5. #include "IObserver.h"  
  6. using std::string;  
  7. class CZhouSiObserver:public IObserver  
  8. {      
  9. public:  
  10.     CZhouSiObserver(void);  
  11.     ~CZhouSiObserver(void);  
  12.     void Update(string context);  
  13.     string GetName();  
  14. private:  
  15.     void Cry(string report);  
  16. };  
  17.   
  18. #endif /* defined(__Observer__ZhouSiObserver__) */  
ZhouSiObserver.cpp

[cpp] view plain copy
  1. #include "ZhouSiObserver.h"  
  2. using std::cout;  
  3. using std::endl;  
  4. using std::string;  
  5.   
  6. CZhouSiObserver::CZhouSiObserver(void):IObserver("周斯")  
  7. {  
  8.       
  9. }  
  10.   
  11. CZhouSiObserver::~CZhouSiObserver(void)  
  12. {  
  13.       
  14. }  
  15.   
  16. //周斯,看到韩非子有活动,自己就受不了  
  17. void CZhouSiObserver::Update(string context)  
  18. {  
  19.     cout << "周斯:观察到韩非子活动,自己也开始活动了..." << endl;  
  20.     this->Cry(context);  
  21.     cout << "周斯:真真的哭死了..." << endl;  
  22. }  
  23.   
  24. //一看李斯有活动,就哭,痛哭  
  25. void CZhouSiObserver::Cry(string report)  
  26. {  
  27.     cout << "周斯:因为" << report.c_str() << ", ————所以我悲伤呀!" << endl;  
  28. }  
  29.   
  30. string CZhouSiObserver::GetName()  
  31. {  
  32.     return m_name;  
  33. }  

被观察者接口:IObservable

IObservable.h

[cpp] view plain copy
  1. #ifndef __Observer__IObservable__  
  2. #define __Observer__IObservable__  
  3.   
  4. #include <iostream>  
  5. #include "IObserver.h"  
  6. using std::string;  
  7.   
  8. class IObservable  
  9. {  
  10. public:  
  11.     IObservable(void){}  
  12.     virtual ~IObservable(void){}  
  13.     //增加一个观察者  
  14.     virtual void AddObserver(IObserver *pObserver) = 0;  
  15.       
  16.     //删除一个观察者,——我不想让你看了  
  17.     virtual void DeleteObserver(IObserver *pObserver) = 0;  
  18.       
  19.     //既然要观察,我发生改变了他也应该用所动作——通知观察者  
  20.     virtual void NotifyObservers(string context) = 0;  
  21.   
  22. };  
  23.   
  24. #endif /* defined(__Observer__IObservable__) */  

被观察者韩非子:HanFeiziObservable类

HanFeiziObservable.h

[cpp] view plain copy
  1. #ifndef __Observer__HanFeiziObservable__  
  2. #define __Observer__HanFeiziObservable__  
  3.   
  4. #include <iostream>  
  5. #include "IObserver.h"  
  6. #include "IObservable.h"  
  7. #include <vector>  
  8. using std::vector;  
  9.   
  10. class CHanFeiziObservable:public IObservable  
  11. {     
  12. public:  
  13.     CHanFeiziObservable(void);  
  14.     ~CHanFeiziObservable(void);  
  15.     void AddObserver(IObserver *pObserver);  
  16.     void DeleteObserver(IObserver *pObserver);  
  17.     void NotifyObservers(string context);  
  18.     //韩非子也是人,也要吃早饭的  
  19.     void HaveBreakfast();  
  20.     //韩非之也是人,是人就要娱乐活动,至于活动时啥,嘿嘿,不说了  
  21.     void HaveFun();  
  22. private:  
  23.     vector<IObserver*> m_observerList;  
  24.     typedef vector<IObserver*>::const_iterator ObserverList_C_iterator;  
  25. };  
  26.   
  27.   
  28.   
  29. #endif /* defined(__Observer__HanFeiziObservable__) */  
HanFeiziObservable.cpp

[cpp] view plain copy
  1. #include "HanFeiziObservable.h"  
  2. using std::string;  
  3. using std::cout;  
  4. using std::endl;  
  5.   
  6. CHanFeiziObservable::CHanFeiziObservable(void)  
  7. {  
  8.       
  9. }  
  10.   
  11. CHanFeiziObservable::~CHanFeiziObservable(void)  
  12. {  
  13.       
  14. }  
  15.   
  16. void CHanFeiziObservable::AddObserver(IObserver *pObserver)  
  17. {  
  18.     m_observerList.push_back(pObserver);  
  19. }  
  20.   
  21. void CHanFeiziObservable::DeleteObserver(IObserver *pObserver)  
  22. {  
  23.     ObserverList_C_iterator it = m_observerList.begin();  
  24.     for (; it != m_observerList.end(); it++)  
  25.     {  
  26.         string name = (*it)->GetName();  
  27.         if (name.compare(pObserver->GetName())==0)  
  28.         {  
  29.             //找到了删除。  
  30.         }  
  31.     }  
  32. }  
  33.   
  34. void CHanFeiziObservable::NotifyObservers(string context)  
  35. {  
  36.     ObserverList_C_iterator it = m_observerList.begin();  
  37.     for(;it != m_observerList.end();it++)  
  38.     {  
  39.         (*it)->Update(context);  
  40.     }  
  41. }  
  42.   
  43. void CHanFeiziObservable::HaveBreakfast()  
  44. {  
  45.     cout << "韩非子:开始吃饭了..." << endl;  
  46.     this->NotifyObservers("韩非子在吃饭");  
  47. }  
  48.   
  49.   
  50. void CHanFeiziObservable::HaveFun()  
  51. {  
  52.     cout << "韩非子:开始娱乐了..." << endl;  
  53.       
  54.     this->NotifyObservers("韩非子在娱乐");  
  55. }  

主程序:main

main.cpp

[cpp] view plain copy
  1. #include <iostream>  
  2. #include "IObserver.h"  
  3. #include "LiSiObserver.h"  
  4. #include "ZhouSiObserver.h"  
  5. #include "IObserver.h"  
  6. #include "HanFeiziObservable.h"  
  7. using std::cout;  
  8. using std::endl;  
  9.   
  10. void DoIt()  
  11. {  
  12.       
  13. }  
  14.   
  15. void DoNew()  
  16. {  
  17.     //IHanFeiZi.h, HanFeiZiNew.h, ILiSi.h, LiSi.h  
  18.     // cout << "----------用新的方法试试----------" << endl;  
  19.       
  20.     //CHanFeiZiNew hanfeizi;  
  21.       
  22.     //hanfeizi.HaveBreakfast();  
  23.       
  24.     //hanfeizi.HaveFun();  
  25. }  
  26.   
  27. void DoNewNew()  
  28. {  
  29.     //IObservable.h, HanfeiziObservable.h, IObserver.h, LiSiObserver.h  
  30.     cout << "----------用更新的方法再试试----------" << endl;  
  31.     //两个观察者产生出来  
  32.     IObserver *pLiSi = new CLiSiObserver();  
  33.     IObserver *pZhouSi = new CZhouSiObserver();  
  34.       
  35.     //定义出韩非子  
  36.     CHanFeiziObservable *pHanFeiZi = new CHanFeiziObservable();  
  37.       
  38.     //我们后人根据历史,描述这个场景,有二个人在观察韩非子  
  39.     pHanFeiZi->AddObserver(pLiSi);  
  40.     pHanFeiZi->AddObserver(pZhouSi);  
  41.       
  42.     //然后这里我们看看韩非子在干什么  
  43.     pHanFeiZi->HaveBreakfast();  
  44.       
  45.     delete pLiSi;  
  46.     pLiSi = NULL;  
  47.     delete pHanFeiZi;  
  48.     pHanFeiZi = NULL;  
  49.       
  50. }  
  51.   
  52.   
  53. int main(int argc, const char * argv[])  
  54. {  
  55.       
  56.     //把李斯这个类聚集到韩非子这个类上,这样的话耦合度太高了,还是用更抽象的方式。  
  57.     DoNew();  
  58.       
  59.     //更抽象的方式,想要观察韩非子的人多了去了,不可能只允许李斯观察。  
  60.     DoNewNew();  
  61.   
  62.     // insert code here...  
  63.     std::cout << "Hello, World!\n";  
  64.     return 0;  
  65. }  

结果如下:




参考文献:《设计模式之禅》,《GoF_23种设计模式解析》

参考博客:  http://www.cnblogs.com/wanggary/archive/2011/04/20/2022975.html

0
阅读全文
0 0
原创粉丝点击