【转】设计模式学习笔记(19)-观察者
观察者模式(Observer)可谓是十分强大啊,它的设计理念比较另类:反过来想。在软件开发中有一个原则叫好莱坞原则,即:Don’t Call Me, I’ll Call you!(不要调用我,我会来调用你!),将控制权翻转,将职责转移了。
何谓观察者模式呢?就比如说你要早起,然后买了一个闹钟,那怎样在早上准时起床呢?一种方案是每个几分钟看一下,如果没到点继续睡觉,到点再起来。显然这种方案太累人了,觉睡不安稳不说,还可能错过时间。我们当然采用另一种方案:设置闹铃时间,到点了就响,这样准时了,并且可以一觉睡到天亮。观察者模式就是第二种方案,你就是观察者(当然不是说你一直在观察,而是说你处于监督对象变化的角色),闹钟就是一个目标(Subject),这就是观察者模式最主要的两个角色。
观察者:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。观察者和目标并没有严格意义上的对应关系,一个观察者可能同时观察多个目标,一个目标也可以同时对多个观察者发出通知。例如:住在同一个宿舍的同学可以共享一个闹钟,当然一个睡得比较死的同学也可能有多个闹钟,并不是一一对应的关系。
观察者模式的类图:
Observer是所有观察者所必须继承的接口,它有一个Update()方法,在Subject更新是自动调用该方法
Subject是所有目标的接口,它维护了一个观察者列表,在自身状态发生改变时对该列表中的所有对象调用update方法
我们来写一个简单的实例:
|
1
2
3
4
5
|
class Observer {public: virtual void Update() = 0;}; |
这是Observer
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Subject{private: vector<Observer*> v;public: void Add(Observer* o) { v.push_back(o); } void Notify() { for(int i = 0; i < v.size(); i++) v.at(i)->Update(); }}; |
这是Subject,为了简单我没有写成接口,直接实现了
|
1
2
3
4
5
6
7
|
class ConcreteObserver : public Observer {public: void Update() { cout << "Updated!" << endl; }}; |
这是实现了的Observer
|
1
2
3
4
|
Subject sub;ConcreteObserver co;sub.Add(&co);sub.Notify(); |
这是主方法
最终输出为
|
1
|
Updated! |
坑爹呢这是?这么简单?对,基本原理就是这样,不过还是有一些值得注意的问题:
1、这个Notify函数应该由谁来调用?我这里在main方法里调用的,实际肯定不能这样,一般放在Subject状态更新之后调用,我这里的Subject根本没有别的方法,其实Subject应该是有变化的。
2、Observer怎样观察多个目标?这很简单,将观察的目标作为Update参数传过去就是了,当然这里并不是一定要传一个应用,可以是某个标识符啊,然后让Observer自己查找Subject就可以了。
3、观察者怎样取得Subject的数据?比如闹钟响的时候我们怎么知道是几点呢(实现不知道的情况下)?一种是我自己看一下,还用一种是使用报时闹钟,分别对应拉(Pull)模型和推(Push)模型,一般来说拉模型更常用一点,因为我可以只取得我自己感兴趣的信息,可以节约数据传输成本,保持安全性。
最后还是来看看适用性吧:
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面
- 当对一个对象的改变需要同时改变其它的对象,而不知道具体有多少对象有待改变
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之,你不希望这些对象是紧密耦合的
值得一提的是,当系统中存在n多观察者和主题时你可能需要一个专用的管理器来进行管理,可以通过表驱动来管理这些对象。
转自: http://lecoding.com/articles/254.html
posted on 2013-03-05 16:31 TheKingOfKingFish 阅读(151) 评论(0) 收藏 举报
浙公网安备 33010602011771号