观察者模式
观察者模式的定义
观察者模式(Observer Pattern)也叫做发布订阅模式(Publish/subscribe),它是一个在项
目中经常使用的模式,其定义如下:
Define a one-to-many dependency between objects so that when one object changes state,all its
dependents are notified and updated automatically.(定义对象间一种一对多的依赖关系,使得每
当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。)
● Subject被观察者
定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类
或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。
● Observer观察者
观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。
● ConcreteSubject具体的被观察者
定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
● ConcreteObserver具体的观察者
每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。
被观察者
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 notifyObservers(){
for(Observer o:this.obsVector){
o.update();
}
}
}
被观察者的职责非常简单,就是定义谁能够观察,谁不能观察,程序中使用ArrayList和
Vector没有太大的差别,ArrayList是线程异步,不安全;Vector是线程同步,安全——就这点
区别。
具体被观察者
public class ConcreteSubject extends Subject {
//具体的业务
public void doSomething(){
/*
* do something
*/
super.notifyObservers();
}
}
观察者
public interface Observer {
//更新方法
public void update();
}
观察者一般是一个接口,每一个实现该接口的实现类都是具体观察者
具体观察者
public class ConcreteObserver implements Observer {
//实现更新方法
public void update() {
System.out.println("接收到信息,并进行处理!");
}
}
场景类
public class Client {
public static void main(String[] args) {
//创建一个被观察者
ConcreteSubject subject = new ConcreteSubject();
//定义一个观察者
Observer obs= new ConcreteObserver();
//观察者观察被观察者
subject.addObserver(obs);
//观察者开始活动了
subject.doSomething();
}
}
观察者模式的优点
● 观察者和被观察者之间是抽象耦合
如此设计,则不管是增加观察者还是被观察者都非常容易扩展,而且在Java中都已经实
现的抽象层级的定义,在系统扩展方面更是得心应手。
● 建立一套触发机制
观察者模式的缺点
观察者模式需要考虑一下开发效率和运行效率问题,一个被观察者,多个观察者,开发
和调试就会比较复杂,而且在Java中消息的通知默认是顺序执行,一个观察者卡壳,会影响
整体的执行效率。在这种情况下,一般考虑采用异步的方式。
观察者模式的使用场景
● 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
● 事件多级触发场景。
● 跨系统的消息交换场景,如消息队列的处理机制。
观察者模式的注意事项
使用观察者模式也有以下两个重点问题要解决。
● 广播链的问题
一个观察者可以有双重身份,既是观察者,也是被观察者,
根据经验建议,在一个观察者模式中
最多出现一个对象既是观察者也是被观察者,也就是说消息最多转发一次(传递两次),这
还是比较好控制的。
注意 它和责任链模式的最大区别就是观察者广播链在传播的过程中消息是随时更改
的,它是由相邻的两个节点协商的消息结构;而责任链模式在消息传递过程中基本上保持消
息不可变,如果要改变,也只是在原有的消息上进行修正。
● 异步处理问题
Java世界中的观察者模式
JDK中提供了:java.util.Observable实现类和java.util.Observer接口
在系统设计中会对观
察者模式进行改造或改装,主要在以下3个方面。
● 观察者和被观察者之间的消息沟通
被观察者状态改变会触发观察者的一个行为,同时会传递一个消息给观察者,这是正确
的,在实际中一般的做法是:观察者中的update方法接受两个参数,一个是被观察者,一个
是DTO(Data Transfer Object,据传输对象),DTO一般是一个纯洁的JavaBean,由被观察者
生成,由观察者消费。
当然,如果考虑到远程传输,一般消息是以XML格式传递。
● 观察者响应方式
观察者是一个比较复杂的逻辑,它要接受被观察者传递过来的
信息,同时还要对他们进行逻辑处理,在一个观察者多个被观察者的情况下,性能就需要提
到日程上来考虑了,
观察者如何快速响应?有两个办法:一是采用多线程技术,甭管
是被观察者启动线程还是观察者启动线程,都可以明显地提高系统性能,这也就是大家通常
所说的异步架构;二是缓存技术,甭管你谁来,我已经准备了足够的资源给你了,我保证快
速响应,这当然也是一种比较好方案,代价就是开发难度很大,而且压力测试要做的足够充
分,这种方案也就是大家说的同步架构。
● 被观察者尽量自己做主
被观察者的状态改变是否一定要通知观察者呢?不一定吧,在设计的
时候要灵活考虑,否则会加重观察者的处理逻辑,一般是这样做的,对被观察者的业务逻辑
doSomething方法实现重载,如增加一个doSomething(boolean isNotifyObs)方法,决定是否通知
观察者,而不是在消息到达观察者时才判断是否要消费。
订阅发布模型
观察者模式也叫做发布/订阅模型(Publish/Subscribe)