观察者模式(Observer)与QQ中的好友登录机制

来源:互联网 发布:软件开发ppt 编辑:程序博客网 时间:2024/05/17 21:58

观察者模式(Observer):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

适用场景:

1、当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用;

2、当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变;

3、当一个对象必须通知其它对象,而它又不能假定其它对象是谁,即这些对象是松耦合的。

通用类图:

当我学习 Observer 模式时,我根据其特点将其映射到一个很常见的场景中,即 QQ 登录。当我登录自己的QQ时,一般情况下我的所有好友都会在主面板上高亮我的头像,表示我上线了。这样的一种机制,和上面 Observer 模式的定义很相似,我与许多好友之间明显是一对多的依赖关系,当我登录时,好友们的QQ面板中我的头像的状态也发生改变了(由暗黑到高亮),而好友们之所以会得知我登录了,就是由类似于 Observer 模式来实现的,即被通知并自动更新。实际上,我认为QQ的这种机制应该是运用了数据库中的触发器机制。

基于上面的例子,我就是被观察者 Subject 主题类,而我的好友们就是观察者 Observer 类,相关方法先看类图,下面再回过头来看看。那么再来相应地分析一下 Observer 模式的适用场景:

1、我和我的许多好友有互相依赖的关系,我可以被任何一位通过我的确认的QQ号码添加为好友,此时好友依赖于我,但是我们之间仍然可以独立封装、独立存在,即就算没有某一位特定的QQ号码添加我为好友时,我还是一位QQ用户。嗯,说得有点杂了,不过应该能理解的;

2、当然,我登录时没必要清楚地知道我有多少好友,QQ服务器尽管通知我的那些应该被通知的好友即可;

3、最后一点,不知道匹配得恰不恰当…当我的某个好友设置了“在线对其隐身”时,那么即使我上线了该好友也不会被通知。在这里,我的设置是事先完成的了,当我上线时,当然也没必要去了解谁被我设置了权限。此时,我和这位特殊的好友是松耦合的。

说了那么多,快点用代码来实现一下(方法名与通用类图中的有所差异):

/** * 抽象的观察者,具有update()方法, * 能够将接收到的信息进行逻辑处理, * 可以是 interface ,不一定是抽象类 */abstractclass Observer {publicabstract void update(String name);}


// 具体观察者01,即QQ好友-01class Observer01extends Observer {publicvoid update(String name) {System.out.println("QQ好友-01 得知" + name + "上线了");}}


// 具体观察者02,即QQ好友-02class Observer02extends Observer {publicvoid update(String name) {System.out.println("QQ好友-02 得知" + name + "上线了");}}


// 具体观察者03,即QQ好友-03class Observer03extends Observer {publicvoid update(String name) {System.out.println("QQ好友-03 得知" + name + "上线了");}}


// 抽象的被观察者,是所有Observer的观察抽象主题abstractclass AbstractSubject {
private ArrayList<Observer> allObservers =new ArrayList<Observer>();// 添加一个观察者,即添加一个QQ好友
public
void addObserver(Observer o) {this.allObservers.add(o);}// 添加一群观察者,即加入一个QQ群
public void addAll(ArrayList<Observer> observers) {this.allObservers.addAll(observers);}// 删除一个观察者,即删除一个QQ好友
public void deleteObserver(Observer o) {this.allObservers.remove(o);}// 删除一群好友,即退出一个QQ群
public void deleteAll() {this.allObservers =null;}// 当我上线时,通知所有QQ好友,即所有Observer
public void notifyObservers(String name) {
for (Observer o : this.allObservers) {
o.update(name);}

}}


// 具体的被观察者,是某些Observer的观察主题class Subject01extends AbstractSubject {
public
void login(String name) {
System.out.println("哈哈...蚂蚁-01 登录 QQ ...");// 立即通知所有QQ好友
super
.notifyObservers(name);
}}


// 测试类publicclass Client {publicstatic void main(String[] args) {// 创建 蚂蚁-01 号
Subject01 subject01 = new Subject01();// 为 蚂蚁-01 号添加好友
Observer observer01 = new Observer01();
Observer observer02 = new Observer02();
Observer observer03 = new Observer03();
subject01.addObserver(observer01);
subject01.addObserver(observer02);
subject01.addObserver(observer03);// 蚂蚁-01 号 登录,好友们马上会被通知
subject01.login("蚂蚁-01 号");System.out.println();// 假如对QQ好友-03隐身,则以后他不会被通知
subject01.deleteObserver(observer03);
subject01.login("蚂蚁-01 号");}}

测试结果:

哈哈...蚂蚁-01 登录 QQ ...
QQ好友-01 得知 蚂蚁-01 号上线了
QQ好友-02 得知 蚂蚁-01 号上线了
QQ好友-03 得知 蚂蚁-01 号上线了
哈哈...蚂蚁-01 登录 QQ ..
.QQ好友-01 得知 蚂蚁-01 号上线了
QQ好友-02 得知 蚂蚁-01 号上线了


很简单的模拟大概就这样了,上面的代码中只有一个 具体Subject01类,而现实生活中 具体Subject类与 具体Observer类 是多对多的关系的,比上面的实现要复杂得多。顾名思义,Observer模式,肯定 Observer类 是相当重要的,它在接收到 具体Subject 的状态改变之后,必须及时进行响应,处理相关事宜。上面的代码中则是得知自己的某个QQ好友上线了。

看一下 Observer 模式的优点:

1、具体 Subject 和具体 Observer 并没有紧耦合,可以各自扩展。在QQ例子中,在本质上 Subject 与 Observer 具有相同的身份,既是观察者也是被观察着,就相当于每个QQ用户都可以不理会自己已有的好友而在添加、删除某一QQ用户,这就是抽象耦合;

2、有时候我们的通知信息是一层一层地传递下去的,此时就形成了一条信息链,这也可以用 Observer 模式来实现,让某个具体 Observer 处理(即 update)信息、事件时出发另一个具体 Observer 对象也进行某些相应操作,也称为触发链,即一个处理序列。不过,多层次的触发回导致更高的复杂性,得把握得好这个度;

Observe 模式与 Chain of Responsibility 模式的对比:

对于上面的触发链,我们可以对比一下职责链模式(Chain of Responsibility),两者都有信息的链传递,不同的是职责链中的信息通常是在传递中不变的,因为该信息旨在遍历整条链而找到第一个能够处理该信息的节点;而 Observer 模式中,假如有触发链,那么这里的信息可能是经过一层一层的“处理-触发-处理-…”逐步变化的。

说到这里,我个人感觉触发链的机制好像有点像 复杂事件处理(CEP),可以比较着了解一下。链接地址:http://www.slideshare.net/Fenng/cep-3915346

Observer 模式的麻烦点:

1、对于某一个具体 Subject 的状态改变,所有具体 Observer 必须逐步 update() ,即业务逻辑处理,如果 Observer 集合过大,那么遍历性能是个问题;

2、根据上面的性能问题,时间延迟也是个问题,如果某个 Observer 需要尽快进行 update() ,如果被长时间堆叠在最后,那就糟了。此时可以用多线程异步进行处理,而多线程中的异步机制又必须保证线程安全。问题一个接一个…

最后,Java 中实际上已经将 Observer 模式囊括在内了,大家看一下文档中 java.util.Observer 接口和 java.util.Observable 类即可,其中的 Observable 相当于 Subject 类。可以试着实现一下。

原创粉丝点击