模式定义
观察者模式(Observer Pattern),又叫 发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式 或 从属者(Dependents)模式。
观察者模式 是对象的行为模式,定义了一种一对多的依赖关系,一个主题对象可被多个观察者对象同时监听,使得每当主题对象状态变化时,所有依赖于它的对象都会得到通知并被自动更新。
观察者模式 核心:松耦合观察者与被观察者,以类似于消息/广播发送的机制联动两者,使被观察者的变动能通知到感兴趣的观察者们,从而做出相应的响应。
主要作用
当系统一方行为依赖于另一方行为的变动时,可使用 观察者模式 松耦合联动双方,使得一方的变动可以通知到感兴趣的另一方对象,从而让另一方对象对此做出响应。
UML类图
角色
抽象主题(Subject):目标又称为主题,指被观察的对象(Observable)。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。
具体主题(ConcreteSubject):具体被观察者,是目标类(抽象主题)的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
抽象观察者(Observer):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。
具体观察者(ConcrereObserver):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。
模式优点
- 观察者和被观察者是松耦合(抽象耦合)的,符合 依赖倒置原则;
- 分离了表示层(观察者)和数据逻辑层(被观察者),并且建立了一套触发机制,使得数据的变化可以响应到多个表示层上;
- 支持广播通信,实现了一对多的通讯机制,支持事件注册机制,支持兴趣分发机制,当被观察者触发事件时,只有感兴趣的观察者可以接收到通知;
- 观察者模式满足 “开闭原则” 的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。
模式缺点
- 如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间;
- 事件通知呈线性关系,如果其中一个观察者处理事件卡壳,会影响后续的观察者接收该事件;
- 如果观察者和被观察者之间存在循环依赖,则可能造成两者之间的循环调用,导致系统崩溃;
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
适用场景
一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用。
一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将发生改变,也不知道这些对象是谁。
需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
实现类似广播机制的功能,无需知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播;
使用步骤
抽象观察者
1 | package main.java.com.study.designPatterns.observer.demoOne; |
抽象主题者
1 | package main.java.com.study.designPatterns.observer.demoOne; |
具体观察者
1 | package main.java.com.study.designPatterns.observer.demoOne; |
具体主题者
1 | package main.java.com.study.designPatterns.observer.demoOne; |
客户端调用
1 | package main.java.com.study.designPatterns.observer.demoOne; |