观察者模式(Observer Pattern),也叫作发布订阅模式(Publish-Subscribe),它定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则全部依赖于它的对象都会获得通知并被自动更新。java
水果店进口水果销量良好,特别是进口蛇果,目前还没到货,有几个女孩小美、小静、小陶想预约进口蛇果,在到货以前就给水果老板说过,等到货后电话或者微信第一时间通知她们。
数组
类图以下
安全
Observer
,当收到被观察者通知后,执行update()
方法;FruitObservable
,持有一个类型为Vector<Observer>
的属性,存放观察者集合,同时定义三个方法addObserver()
,deleteObserver()
,notifyObservers()
,分别为添加预约顾客,删除预约顾客,通知已预订顾客;FruitObservable
抽象接口的实现类为进口蛇果ImportedRedDeliciousApple
;Observer
接口的实现类为预约进口蛇果的客户类CustomerObserver
;代码实现以下微信
package com.wzj.observer.example1; /** * @Author: wzj * @Date: 2019/10/3 14:53 * @Desc: 观察者接口类 */ public interface Observer { //收到通知后观察者更新 void update(); }
package com.wzj.observer.example1; import java.util.Vector; /** * @Author: wzj * @Date: 2019/10/3 14:50 * @Desc: 水果店被观察者类 */ public abstract class FruitObservable { //线程安全的容器类 protected Vector<Observer> obs = new Vector<>(); //添加预约顾客 public void addObserver(Observer o) { obs.addElement(o); } //删除固定顾客 public void deleteObserver(Observer o) { obs.removeElement(o); } //通知已预约顾客 public abstract void notifyObservers(); }
package com.wzj.observer.example1; /** * @Author: wzj * @Date: 2019/10/3 15:19 * @Desc: 进口蛇果类 */ public class ImportedRedDeliciousApple extends FruitObservable { @Override public void notifyObservers() { System.out.println("通知: 进口蛇果已到..."); for(Observer o : obs) { //通知每位预约顾客 o.update(); } } }
package com.wzj.observer.example1; /** * @Author: wzj * @Date: 2019/10/3 15:25 * @Desc: 预约进口蛇果的客户类 */ public class CustomerObserver implements Observer { //观察者姓名 private String name; public CustomerObserver(String name){ this.name = name; } @Override public void update() { System.out.println(name + "已收到通知, 将立马过来购买!"); } }
客户端测试类多线程
package com.wzj.observer.example1; /** * @Author: wzj * @Date: 2019/10/3 15:38 * @Desc: */ public class Client { public static void main(String[] args) { //进口蛇果 ImportedRedDeliciousApple apple = new ImportedRedDeliciousApple(); //初始化预约客户类 CustomerObserver mei = new CustomerObserver("小美"); CustomerObserver jing = new CustomerObserver("小静"); CustomerObserver tao = new CustomerObserver("小陶"); //将小美、小静、小陶加入水果店的预约客户列表中 apple.addObserver(mei); apple.addObserver(jing); apple.addObserver(tao); //通知客户 apple.notifyObservers(); } }
执行结果以下app
通知: 进口蛇果已到... 小美已收到通知, 将立马过来购买! 小静已收到通知, 将立马过来购买! 小陶已收到通知, 将立马过来购买!
类图以下
异步
Observer
,当收到被观察者通知后,执行update()
方法;Observable
,boolean
类型的属性changed
表示状态是否变化,持有一个类型为Vector<Observer>
的属性obs
;Observable
抽象接口的实现类为进口蛇果ImportedRedDeliciousApple
;Observer
接口的实现类为预约进口蛇果的客户类CustomerObserver
;代码实现以下ide
package com.wzj.observer.example2; import java.util.Observable; import java.util.Observer; /** * @Author: wzj * @Date: 2019/10/3 17:09 * @Desc: 预约客户类,继承观察者接口 */ public class CustomerObserver implements Observer { private String name; public CustomerObserver(String name){ this.name = name; } @Override public void update(Observable o, Object arg) { System.out.println(name + "已收到通知, 将立马过来购买!"); } }
package com.wzj.observer.example2; import java.util.Observable; import java.util.Observer; /** * @Author: wzj * @Date: 2019/10/3 17:02 * @Desc: 进口蛇果类,继承jdk的Observable接口 */ public class ImportedRedDeliciousApple extends Observable { public void peform() { System.out.println("通知: 进口蛇果已到..."); //设置状态改变 this.setChanged(); this.notifyObservers(); } }
客户端代码以下源码分析
package com.wzj.observer.example2; /** * @Author: wzj * @Date: 2019/10/3 15:38 * @Desc: 使用jdk自带的Observable类和Observer接口 */ public class Client { public static void main(String[] args) { //进口蛇果 ImportedRedDeliciousApple apple = new ImportedRedDeliciousApple(); //初始化预约客户类 CustomerObserver mei = new CustomerObserver("小美"); CustomerObserver jing = new CustomerObserver("小静"); CustomerObserver tao = new CustomerObserver("小陶"); //将小美、小静、小陶加入水果店的预约客户列表中 apple.addObserver(mei); apple.addObserver(jing); apple.addObserver(tao); //通知客户 apple.peform(); } }
执行结果测试
通知: 进口蛇果已到... 小陶已收到通知, 将立马过来购买! 小静已收到通知, 将立马过来购买! 小美已收到通知, 将立马过来购买!
源码分析
/** 被观察者 */ public class Observable { private boolean changed = false; private Vector<Observer> obs; /** 构造方法 */ public Observable() { obs = new Vector<>(); } /** 添加观察者,并加同步控制保证多线程安全 */ public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } /** 删除观察者,并加同步控制保证多线程安全 */ public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } /** 通知观察者 */ public void notifyObservers() { //通知全部观察者 notifyObservers(null); } public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { //状态未改变时返回 if (!changed) return; //状态改变后,将集合转为数组 arrLocal = obs.toArray(); //状态恢复初始值 clearChanged(); } //遍历数组,逐个通知观察者 for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } /** 状态改变 */ protected synchronized void setChanged() { changed = true; }
优势
观察者和被观察者之间是抽象耦合。
无论是增长观察者仍是被观察者都很是容易扩展,并且在Java中都已经实现的抽象层级的定义,因此尽可能使用JDK自带的接口。
与责任链结合使用
在不少系统中,Observer模式每每和责任链共同负责对于事件的处理,其中的某一个observer负责是否将事件进一步传递。
缺点
观察者模式须要考虑一下开发效率和运行效率问题,一个被观察者,多个观察者,开发和调试就会比较复杂,并且在Java中消息的通知默认是顺序执行,一个观察者卡壳,会影响总体的执行效率。在这种状况下,通常考虑采用异步的方式。