首页 > 代码库 > 面向对象语言设计模式 —— 观察者模式
面向对象语言设计模式 —— 观察者模式
什么是观察者?
观察者模式顾名思义就是很多个 类观察主要的类,如果主要的类一旦触发事件,就会通知所有的 观察者类。
如果你不理解观察者模式,我将用一些比较简单的说明来让你理解。
如图
这样说来,所有订报纸的就是观察者,报社就是线程,报社(线程)触发了事件之后会告诉卖报纸(主题)的,叫他去送报纸(发送事件).然后我们观察者就之后了
这有什么用?
或许有人在学习新知识之前,会问这玩意有什么用,其实我个人认为,观察者设计模式一般用于监听鼠标事件,键盘事件或者其他自定义事件。
因为我们基本上都是写好一个函数,然后等待事件就好了。
那么。代码应该如何实现呢?由于在《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>
面向对象语言设计模式 —— 观察者模式