引子
观察者模式是设计模式中行为模式的一种,在我们的日常编程中可能使用并不频繁,但却是各大技术和中间件中经常涉足的一个模式,设计上更显得高大上。比如NIO、JMS、Vue.js、Spring Cloud等,都用到了观察者模式或其思路。下面我们来详细学习它。
场景
某家科技公司目前在开发一个项目,设计小组需要上报项目的进度给部门经理,主要有包括更新原有的业务模块进度和添加新业务的模块完成进度。那么部门经理需要什么途径能最快的得到进度的信息呢?或者可能是项目总监也想去获取到最新的进展情况呢?我们该如何去处理呢?
很多时候我们就会想到继承去解决这一情况,毕竟面向对象思想时刻影响这一我们,但是如果某天项目经理出差了,他不想看项目进度了,那我们又改怎么办呢?
我们能不能就是设计一个业务,让能想知道该进度的人,不管什么时候,只要有开发者上报进度的时候就一下他就得到进度的信息,而他无需去关心这个过程。
你是否能想到合适的解决方案呢?当然就是观察者。
含义
什么是观察者模式?
观察者模式定义一系列对象之间的一对多关系,当一个对象改变、更新状态时,依赖它的都会收到通知改变或者更新。
为什么需要观察者模式?
从定义中我们可以知道观察者模式当对象改变时,其他依赖的对象都会收到改变信息的状态。
从本例分析项目经理想知道进度情况,他只需要绑定进度,他就可以知道进度信息了,而无需关心如何操作,如果再增加一个想知道进度的人呢?也很容易,也让他绑定进度信息数据就好了,不想知道的时候就解除绑定,就不在获取进度信息了。
如何实现观察者模式?
自定义观察者模式
我们先来看一下这个UML类图进行分析
![b0eadb3da332bf882b571ce25545e62f.png](https://i-blog.csdnimg.cn/blog_migrate/c429788b0770fab337d49e911327210a.jpeg)
具体实现步骤
1.构造一个主题Subject或者是一个被观察者Observeable,这是一个接口或者是抽象类
public interface Subject { //注册观察者 void registerObserver(Observer observe); //解除绑定观察者 void unRegisterObserver(Observer observe); //更新数据 void notifyObservers(); }
2.构建一个被观察者的实现,DevelopmentProgressData
registerObserver(Observer o);//方法中将观察者添加到注册列表中
unRegisterObserve(Observer o);//删除观察者
public class DevelopmentProgressData implements Subject { private ArrayList arrayObserve; private int completeProgress;//完成进度 private int updateProgress;//更新进度 public DevelopmentProgressData() { arrayObserve = new ArrayList(); } @Override public void registerObserver(Observer observer) { //将观察者添加到列表中 arrayObserve.add(observer); } @Override public void unRegisterObserver(Observer observer) { int i = arrayObserve.indexOf(observer); if (i >= 0) { //将观察者从列表中解除 arrayObserve.remove(i); } } //通知所以观察者数据更新了 @Override public void notifyObservers() { for (int i = 0; i < arrayObserve.size(); i++) { Observer o = (Observer) arrayObserve.get(i); o.update(completeProgress, updateProgress); } } //更新数据 public void setCurrentData(int completeProgress, int updateProgress){ this.completeProgress = completeProgress; this.updateProgress = updateProgress; notifyObservers }}
3.创建一个观察者接口Observer
public interface Observer { //更新数据 void update(int completeProgress, int updateProgress); }
4.构建具体的观察者实现(相当于上面例子的项目经理),需实现接口Observes,
将主题Subject通过构造函数传入并向其注册观察者,如 ProductManagerObserver
调用 developmentProgressSubject.registerObserver(this);将观察者注册到观察列表中
public class ProductManagerObserver implements Observer { private int completeProgress;//完成进度 private int updateProgress;//更新进度 //将主题当成观察者的属性 private Subject developmentProgressSubject; public ProductManagerObserver(Subject developmentProgressSubject) { this.developmentProgressSubject = developmentProgressSubject; //注册该观察者 developmentProgressSubject.registerObserver(this); } @Override public void update(int completeProgress, int updateProgress) { this.completeProgress = completeProgress; this.updateProgress = updateProgress; }}
测试
public class RunTest { public static void main(String[] args) { Subject developmentProgressData = new DevelopmentProgressData(); Observer productManagerObserver = new ProductManagerObserver(developmentProgressData); Observer projectManagerObserver = new ProjectManagerObserver(developmentProgressData); //更新数据并通知观察者,产品经理和项目经理均可获得信息 developmentProgressData.setCurrentData(34, 45); //当项目经理出差了,不观察项目进度了就取消订阅了 developmentProgressData.unRegisterObserver(projectManagerObserver); //更新数据并通知观察者,当前只有产品经理科获取信息 developmentProgressData.setCurrentData(46, 90); }}
输出结果
产品经理管理者显示当前数据 完成进度为: 34更新修改进度为:45项目管理真显示当前数据完成进度为: 34更新修改进度为:45产品经理管理者显示当前数据 完成进度为: 46更新修改进度为:90
根据java.util.observable实现观察者模式
具体实现步骤
1.首先观察者需要实现java.util.Observer,然后将其被观察者java.util.Observable传入其观察者的构造中
public class BossMngObserver implements Observer { private Observable observable; private int valuableProductNum; //库存有贵重产品 private int normalProductNum; //普通产品 public BossMngObserver(Observable observable) { this.observable = observable; //通过observerable.addObserver(this)添加观察者 observable.addObserver(this); } //实现 Observer更新数据方法 @Override public void update(Observable o, Object arg) { if (o instanceof InventoryData) { InventoryData inventoryData = (InventoryData) o; this.valuableProductNum = inventoryData.getValuableProductNum(); this.normalProductNum = inventoryData.getNormalProductNum(); } }}
2.被观察者需要继承java.util.Observerable
public class InventoryData extends Observable { private int valuableProductNum; //库存有贵重产品 private int normalProductNum; //普通产品 public void setCurrentData(int valuableProductNum, int normalProductNum) { this.valuableProductNum = valuableProductNum; this.normalProductNum = normalProductNum; //调用notifyObserves()更新数据 setChanged(); notifyObservers(); } }
测试
3.Test.class
public class Test { public static void main(String[] args) { //创建被观察者 InventoryData inventoryData = new InventoryData(); //创建观察者 ValuableInfoMngObserver io = new ValuableInfoMngObserver(inventoryData); //io.deleteObserve(); //更新数据通知观察者 inventoryData.setCurrentData(20, 30); //创建观察者 NormalInfoMngObserver no = new NormalInfoMngObserver(inventoryData); //no.deleteObserver(); //更新数据通知观察者 inventoryData.setCurrentData(15, 27); //创建观察者 BossMngObserver bossMngObserver = new BossMngObserver(inventoryData);//更新数据通知观察者 inventoryData.setCurrentData(10, 50); }}