面向对象语言设计模式 —— 观察者模式
Posted Suwings
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象语言设计模式 —— 观察者模式相关的知识,希望对你有一定的参考价值。
什么是观察者?
观察者模式顾名思义就是很多个 类观察主要的类,如果主要的类一旦触发事件,就会通知所有的 观察者类。
如果你不理解观察者模式,我将用一些比较简单的说明来让你理解。
如图
这样说来,所有订报纸的就是观察者,报社就是线程,报社(线程)触发了事件之后会告诉卖报纸(主题)的,叫他去送报纸(发送事件).然后我们观察者就之后了
这有什么用?
或许有人在学习新知识之前,会问这玩意有什么用,其实我个人认为,观察者设计模式一般用于监听鼠标事件,键盘事件或者其他自定义事件。
因为我们基本上都是写好一个函数,然后等待事件就好了。
那么。代码应该如何实现呢?由于在《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>
以上是关于面向对象语言设计模式 —— 观察者模式的主要内容,如果未能解决你的问题,请参考以下文章
JAVA SCRIPT设计模式--行为型--设计模式之Observer观察者模式(19)