程序设计模式 —— 观察者模式

 什么是观察者?


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

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

如图

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

这有什么用?


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

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

那么。代码应该如何实现呢?由于在《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 Observer
3 {
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);//add
22     };
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 Observer
14 {
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>

原文地址:https://www.cnblogs.com/suwings/p/5903326.html