首页 > 代码库 > 面向对象语言设计模式 —— 观察者模式

面向对象语言设计模式 —— 观察者模式

 什么是观察者?


 

观察者模式顾名思义就是很多个 类观察主要的类,如果主要的类一旦触发事件,就会通知所有的 观察者类。

如果你不理解观察者模式,我将用一些比较简单的说明来让你理解。

如图

技术分享

这样说来,所有订报纸的就是观察者,报社就是线程,报社(线程)触发了事件之后会告诉卖报纸(主题)的,叫他去送报纸(发送事件).然后我们观察者就之后了

 

这有什么用?


 

或许有人在学习新知识之前,会问这玩意有什么用,其实我个人认为,观察者设计模式一般用于监听鼠标事件,键盘事件或者其他自定义事件。

因为我们基本上都是写好一个函数,然后等待事件就好了。

那么。代码应该如何实现呢?由于在《head First》 里面已经有Java的实现了,所以我就用C++语言写了一下。

 

框架图


 

首先大致框架图:

技术分享

大致如上

其中Shell就是 卖报的。所有 卖报的就要实现 Subject 接口(一般而言就一个,当然了你也可以多对多)

Shellp pash ids 都是订报纸的。所有要定报纸的都必须实现 Observe 接口

代码如下:

注意要加上:

1 #include <iostream>2 #include <vector>  //可以去搜索一下  vector 如何用,如果你熟悉java,可认为它是 ArrayList 类3 4 using namespace std;

 

具体代码实现


首先我们先实现 基类

1 /*观察者抽象基类*/2 class Observer3 {4 public:5     //这里的参数 之所以用string 是为了告诉你可以类传递,甚至也可以传递其他6     virtual void updata(const char* str) = 0;7     //注意,在你真实项目中用的时候,应该写一个虚的析构函数8 9 };
 1 /*主题 抽象基类*/ 2 class Subject 3 { 4 public: 5  6     virtual void eventObserver() = 0;    //事件触发!其他程序来用 7     virtual void registerObserver(Observer *) = 0;    //注册成为观察者 8     virtual void removeObserver(Observer *) = 0;    //管理者删除自己 9 10 };

 

好了,基本上是这样。那么我们来实现主题:继承subject

 1 /*Shell 继承主题*/ 2 class Shell : public Subject 3 { 4 private: 5     std::vector <Observer*> list; 6  7 public: 8     //实现方法 9     inline virtual void eventObserver()10     {11         vector<Observer*>::iterator it;12         int z=0;13         for (it = list.begin(); it < list.end();it++,z++)    //代送器遍历14         {15 16             (*it)->updata("Hello!");   //向每一个 观察者(监听者) 触发Observe 基类的函数,相当于发送事件17         }18     };19     inline virtual void registerObserver(Observer * ob)//注册成为观察者20     {21         list.push_back(ob);//add22     };23     inline virtual void removeObserver(Observer * ob)24     {25         vector<Observer*>::iterator it;26         int z=0;27         for (it = list.begin(); it < list.end();it++,z++)    //代送器遍历28         {29             if (&ob == &*it){30                 //如果地址相同 删除31                 list.erase(list.begin()+z);32             }33         }34     };35 };

 

然后我们如概念图,我们节约时间,只实现两个 观察者(相当于就是 事件的监听者)

 1 /*Dis 观察者*/ 2 class Dis : public Observer 3 { 4 public: 5     inline virtual void updata(const char* str)  //这个是Observe基类的方法,这里对其实现,主题(Shell类)会调用这个方法。触发事件 6     { 7         cout << "[Dis] DataGet :"<< str << endl; 8     }; 9 };10 11 12 /*Pash 观察者*/13 class Pash : public Observer14 {15 public:16     inline virtual ~Pash()17     {18 19     };20     inline Pash()21     {22 23     };24     inline virtual void updata(const char* str)   //这个是Observe基类的方法,这里对其实现,主题(Shell类)会调用这个方法。触发事件25     {26         cout << "[Pash] DataGet :" << str << endl;27     };28 };

上面分别写了两个类,两个类都实现了 updata函数。而且有不同的输出(功能)。

 

下面我们来运行试试?

 1 /*主函数*/ 2 int main() 3 { 4     Pash *pash = new Pash(); 5     Dis *dis = new Dis(); 6     Dis *dis2 = new Dis(); 7     Dis *dis3 = new Dis(); 8     Shell shell; 9     //初始化10 11     shell.registerObserver(pash);    //注册12     shell.registerObserver(dis);13     shell.registerObserver(dis2);14     shell.registerObserver(dis3);15 16     shell.removeObserver(dis3);    //删除dis3 17 18     //触发事件19     shell.eventObserver();    //这一行不一定非得写在这里,可以在任何需要触发的地方(其他线程)触发20 21     //这一行无视~我是用Sublime写的,所以加个这个东西看输出22     std::cin.get();23     return 0;24 }

输出:

技术分享

 

 

那么到现在为止,我们到底做了什么?


可以看见,这一行:

将 Observe 的子类 Dis(观察者)注册到了 Shell 类(主题)中。并且随时可以等待事件,所有的都一样。

1 shell.registerObserver(dis);


从其他的地方激活事件,然后shell类(主题)就会告诉所有的已经注册了的 Observe 的子类(观察者),触发 “ virtual void updata(const char* str) ”函数;

1  shell.eventObserver();    //这一行不一定非得写在这里,可以在任何需要触发的地方(其他线程)触发

 

怎么触发的呢?

可以去看看Shell类的16行 “ (*it)->updata("Hello!"); ” 对每个 已经注册了的 Observe 子类进行触发。

 

至此,这就是观察者设计模式。

 

最后


但是要注意的一点,不是说有了这个观察者模式,就必须要加进去使用,程序会更棒。

设计模式要与你的程序相互和谐,不能写个 “HelloWorld” 程序都用到了设计模式。

总的一句话,设计模式不是规则,而是你随时可以改变的模式。这也是很多设计模式书籍强调的一点。

 

 

<Thanks>不论对你是否有帮助,还是谢谢您的耐心查看。如有错误之处,还望指教。</Thanks>

面向对象语言设计模式 —— 观察者模式