《设计模式》之十五:观察者模式
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.
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
观察者模式的几个角色名称:
1,Subject被观察者
定义被观察者必须实现的职责,它必须能够动态增加、删除观察者,它一般是抽象类或实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者
2,Observer观察者
观察者接受到消息后,立即进行update,对接受的信息进行处理
3,ConcreteSubject具体的被观察者
定义被观察者自己的业务逻辑,同时定义对那些事件进行通知
4,ConcreteObserver具体观察者
通用模板代码:
public interface Observer {
// 更新方法
public void update();
}public class ConcreteObserver implements Observer {
@Override
public void update() {
System.out.println("接受到消息,并处理中...");
}
}public abstract class Subject {
// 定义一个观察者数组
private Vector<Observer> observers = new Vector<Observer>();
// 增加一个观察者
public void addObserver(Observer o) {
this.observers.add(o);
}
// 删除一个观察者
public void delObserver(Observer o) {
this.observers.remove(o);
}
// 通知所有观察者
public void notifyObservers() {
for (Observer o : observers) {
o.update();
}
}
}public class ConcreteSubject extends Subject {
// 具体业务逻辑
public void doSomething() {
// do something...
System.out.println("I do something...");
super.notifyObservers();
}
}public class Client {
public static void main(String[] args) {
// 创建一个被观察者
ConcreteSubject subject = new ConcreteSubject();
// 定义一个观察者
Observer obs = new ConcreteObserver();
// 添加观察者
subject.addObserver(obs);
// 开始活动
subject.doSomething();
}
}观察者模式的优点:
1,观察者和被观察者之间是抽象耦合的
如此则不管是增加观察者还是增加被观察者都非常容易扩展,而且在Java中都已经实现的抽象层的定义,在系统扩展方面更是得心应手。
2,建立一套除非机制
观察者模式的缺点:
观察者模式需要考虑一下开放效率和运行效率问题,一个被观察者,多个观察者,开放和调试就比较复杂。Java中消息通知模式是顺序执行,这种情况下,一般采用异步方式的消息通知机制。
多级触发的效率更是让人担忧。这时候要注意啦啦
观察者模式使用场景:
1,关联行为场景。注意的是,关联行为是可拆分的,而不是组合关系。
2,事件多级触发场景
3,扩系统的消息交换场景,如消息队列的处理机制
注意事项:
广播链的问题:
只要注意一点,根据经验建议,一个观察者模式中最多出现一个对象既是观察者又是被观察者,也就是说消息最多转发一次(传递两次)。
异步处理问题:
有多个观察者的时候,如果观察者处理时间较长就要使用异步方式,那这个时候就得考虑线程安全和队列的问题,这时候可以参考下Message Queue就有更深入的理解。
观察者模式的扩展模式:
在JDK中已经给我们提供了现成的Observable和Observer两个类,之间使用即可大大简化上面的代码:
这时候已经不需要抽象的Subject和自己定义的Observer类了:
public class ConcreteSubject extends Observable {
// 具体业务逻辑
public void doSomething() {
// do something...
System.out.println("I do something...");
super.setChanged();
super.notifyObservers();
}
}public class ConcreteObserver implements java.util.Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("---哈哈,我在使用JDK里面的Observer接受到消息---");
}
}项目中真实的观察者模式:
1,观察者和被观察者之间的消息沟通
一般做法是:观察者中的update方法有两个参数,一个是被观察者,一个是DTO,DTO是一个纯洁的JavaBean,由被观察者生产,由观察者消费。 从JDK的Observer接口即可看出来。
如果考虑远程传输,一般消息格式以XML或者JSON格式传递。
2,观察者响应方式:
一般来讲是启动多线程去通知观察者
3,被观察者尽量自己做主
被观察者状态改变是否一定要通知观察者呢?不一定的这个,一般对被观察者的业务逻辑doSomething方法实现重载,如增加一个doSomething(boolean isNotifyObs)方法,决定是否通知观察者,而不是在消息到达观察者时才判断要不要处理这个消息。
最佳实践:
观察者模式在实践项目和生活中经常出现,举几个例子说明:
1,文件系统
一个目录小新建一个文件,会同时通知目录管理器增加一个目录,并通知磁盘管理器减少1K空间
2,广播收音机
电台在广播,你可以打开两个收音机来收听,电台就是被观察者,收音机就是观察者。
本人博客已搬家,新地址为:http://yidao620c.github.io/