设计模式之16观察者模式(笔记)
来源:互联网 发布:数据库数字类型 编辑:程序博客网 时间:2024/04/29 11:41
1 定义:Observer Pattern,也叫做发布订阅模式(Publish / subscribe)
1.1 定义:Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.(定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。)
1.2 通用类图:
1.3 通用代码:
public abstract class Subject {// 定一个一个观察者数组private Vector<Observer> obsVector = new Vector<Observer>();// 增加一个观察者public void addObserver(Observer o) {this.obsVector.add(o);}// 删除一个观察者public void delObserver(Observer o) {this.obsVector.remove(o);}// 通知所有观察者public void notifyObserver() {for (Observer o : this.obsVector) {o.update();}}}public interface Observer {// 更新方法public void update();}public class ConcreteSubject extends Subject {// 具体的业务public void doSomething() {/* * do something */super.notifyObserver();}}public class ConcreteObserver implements Observer {// 实现更新方法public void update() {System.out.println("接收到信息,并进行处理!");}}public class Test {public static void main(String[] args) {// 创建一个被观察者ConcreteSubject subject = new ConcreteSubject();// 定义一个观察则Observer obs = new ConcreteObserver();// 观察者观察被被观察则subject.addObserver(obs);// 观察者开始活动了subject.doSomething();}}
2 优点
2.1 观察者与被观察者之间是抽象耦合:因此无论是增加观察者还是增加被观察者,都十分容易。
2.2 可以经过扩展,从而建立一条链状的触发机制。
3 缺点
3.1 在Java中消息的通知默认是顺序执行,一个观察者卡壳,会影响整体的执行效率。这时可以考虑采用异步的方式。(多线程呗)
3.2 多级触发时的效率更让人担忧,设计时需考虑。(就是上面所说的链状触发)
4 应用场景
4.1 使用关联行为的场景。注意是可拆分的关联,而非组合。
4.2 事件多级触发场景。
4.3 跨系统的消息交换场景,如消息队列的处理机制。(如kkPlayer的全局快捷键)
5 注意事项
5.1 广播链的问题:在一个观察者模式中最多出现一个对象既是观察者又是被观察者,消息转发最多一两次,还比较好控制。
5.2 异步处理问题:需要考虑线程安全和队列的问题。(可以参考Message Queue)
6 扩展
6.1 Java世界中观察者模式
在前面的通用类图及其源代码实现中,通过观察你也许会发现,抽象的被观察者subject仅帮我们关联了观察者和确定了通知机制;抽象的观察者仅确立了被通知的方法。
这些完全可以单独抽象出一个联络类,作为观察者或被观察者的职责,这样就很非常符合单一职责原则。
幸运的是,Java从天始诞生就提供了一个可扩展的父类,即Java.util.Observable,这个类专用于让别人去触发,Java.util.Observer接口则专注于对观察者通知。
此外,还应关注Java.util.Observer接口丰富的方法,可以动态的添加/删除观察者。
6.2 项目中真实的观察者模式:
因为前面讲解的都是太标准的模式,在系统设计中会对观察者模式进行改造或改装,主要是下面三方面。
A。观察者与被观察者之间的消息沟通:被观察者状态改变时会触发观察者的一个行为,同时会传递一个消息给观察者,在实际中一般的做法是:观察者中的update方法接受两个参数,一个是被观察者,一个是DTO(Data Transfer Object,数据传输对象),DTO一般是一个纯JavaBean,由被观察者生成,由观察者消费。(若远程,则以XML格式传递)
B。观察者响应方式:观察者是个比较复杂的逻辑,要接受被观察者传递过来的信息,同时还要对他们进行逻辑处理,如果一个观察者对应多个被观察者,则需要考虑性能。备选方法两个:一是多线程,一是缓存技术。
C。被观察者尽量自己做主:不要把消息传到观察者时才判断是否需要消费。
应用举例:
文件系统:当在目录下新建一个文件,这个动作会同时通知目录管理器增加该目录,并通知磁盘管理器减少1KB的空间,也就是“文件”是一个被观察者,“目录管理器”则是观察者。
猫鼠游戏:猫叫一声,惊动了鼠;
广播收音机:电台在广播,收音机就能收听。
7 范例
7.1 标准的“观察者模式”可以参考通用源码
7.2 这里使用原书例子,使用java提供的观察者服务类。
类图如下:
需要注意的是,源码中有模拟处理耗时的情况,当然默认并没有多线程支持。。。
源代码如下:(作者原书例)
import java.util.Observable;/** * @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you * all. 韩非子,李斯的师弟,韩国的重要人物 */public class HanFeiZi extends Observable {// 韩非子要吃饭了public void haveBreakfast() {System.out.println("韩非子:开始吃饭了...");// 通知所有的观察者super.setChanged();super.notifyObservers("韩非子在吃饭");}// 韩非子开始娱乐了,古代人没啥娱乐,你能想到的就那么多public void haveFun() {System.out.println("韩非子:开始娱乐了...");super.setChanged();this.notifyObservers("韩非子在娱乐");}}public class LiSi implements Observer {// 首先李斯是个观察者,一旦韩非子有活动,他就知道,他就要向老板汇报public void update(Observable observable, Object obj) {System.out.println("李斯:观察到李斯活动,开始向老板汇报了...");this.reportToQiShiHuang(obj.toString());System.out.println("李斯:汇报完毕,秦老板赏给他两个萝卜吃吃...\n");try {System.out.println("我开始休眠 " + System.currentTimeMillis());Thread.sleep(3000);System.out.println("我起来了 " + System.currentTimeMillis());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}// 汇报给秦始皇private void reportToQiShiHuang(String reportContext) {System.out.println("李斯:报告,秦老板!韩非子有活动了--->" + reportContext);}}public class LiuSi implements Observer {// 刘斯,观察到韩非子活动后,自己也做一定得事情public void update(Observable observable, Object obj) {System.out.println("刘斯:观察到韩非子活动,开始动作了...");this.happy(obj.toString());System.out.println("刘斯:真被乐死了\n");}// 一看韩非子有变化,他就快乐private void happy(String context) {System.out.println("刘斯:因为" + context + ",——所以我快乐呀!");}}public class WangSi implements Observer {// 王斯,看到李斯有活动,自己就受不了public void update(Observable observable, Object obj) {System.out.println("Observable = " + observable.getClass()+ " , obj = " + obj);System.out.println("王斯:观察到韩非子活动,自己也开始活动了...");this.cry(obj.toString());System.out.println("王斯:真真的哭死了...\n");}// 一看李斯有活动,就哭,痛哭private void cry(String context) {System.out.println("王斯:因为" + context + ",——所以我悲伤呀!");}}public class Client {public static void main(String[] args) {// 三个观察者产生出来Observer liSi = new LiSi();Observer wangSi = new WangSi();Observer liuSi = new LiuSi();// 定义出韩非子HanFeiZi hanFeiZi = new HanFeiZi();// 我们后人根据历史,描述这个场景,有三个人在观察韩非子hanFeiZi.addObserver(wangSi);hanFeiZi.addObserver(liuSi);hanFeiZi.addObserver(liSi);// 然后这里我们看看韩非子在干什么hanFeiZi.haveBreakfast();}}
测试结果:
韩非子:开始吃饭了...
李斯:观察到李斯活动,开始向老板汇报了...
李斯:报告,秦老板!韩非子有活动了--->韩非子在吃饭
李斯:汇报完毕,秦老板赏给他两个萝卜吃吃...
我开始休眠 1337226592828
我起来了 1337226595828
刘斯:观察到韩非子活动,开始动作了...
刘斯:因为韩非子在吃饭,——所以我快乐呀!
刘斯:真被乐死了
Observable = class _16_Observer.HanFeiZi , obj = 韩非子在吃饭
王斯:观察到韩非子活动,自己也开始活动了...
王斯:因为韩非子在吃饭,——所以我悲伤呀!
王斯:真真的哭死了...
- 设计模式之16观察者模式(笔记)
- 设计模式笔记之观察者
- 学习笔记 ---- 设计模式之观察者模式
- 设计模式之观察者模式学习笔记
- 设计模式学习笔记之观察者模式
- 设计模式笔记之---观察者模式
- 设计模式笔记之观察者模式
- Java设计模式笔记之观察者模式
- 设计模式学习笔记之观察者模式
- 设计模式学习笔记之观察者模式
- 设计模式学习笔记之观察者模式
- 设计模式之禅笔记-观察者模式
- 设计模式之观察者模式--慕课网笔记
- 设计模式之观察者模式-笔记
- 设计模式笔记之观察者模式(Observer Patterns)
- 设计模式---观察者模式(学习笔记)
- 【16】设计模式之-----观察者模式
- 设计模式 笔记 观察者模式
- 设计模式之15组合模式(笔记)
- io拷贝
- 试译雷神的微软平台安全宝典第二章 简介和RSA章节
- ant和yuicompressor 压缩css、js方案
- 缓冲
- 设计模式之16观察者模式(笔记)
- SQL Server 2005 导入数据 请注意事项
- 每天一本书不再是问题——快速阅读
- 开发snmp rddtools
- 嵌入式Linux的GDB调试环境建立
- windows 进程间通信(共享内存)
- typedef struct _DRIVER_OBJECT
- 设计模式之17门面模式(笔记)
- 复习笔记8 位映射实现的权限管理