《设计模式》之十五:观察者模式
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/