本文共 7275 字,大约阅读时间需要 24 分钟。
用报纸订阅的方式来说明:
1、报社的业务就是出版报纸
2、向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,就会一直收到报纸
3、当你不想再看报纸的时候,取消订阅,他们就不会再送来新报纸
4、只要报社还在运营,就会一直有人向他们订阅报纸或者取消订阅报纸
观察者模式的流程跟报纸订阅方式一致,即:观察者模式=出版者+订阅者,只是名称不一样,出版者改称为“主题”(Subject),订阅者改称为“观察者”(Observer)。
观察者定义:
观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。
主题接口(Subject):对象使用此接口注册为观察者,或者把自己从观察者中删除。
具体主题(ConcreteSubject):一个具体主题总是实现主题接口,除了注册*和撤销方法以外,具体主题还实现了notifyObserves()方法,此方法用于在状态改变时更新所有当前观察者。
观察者(Observer):为那些在目标发生改变时需获得通知的对象定义更新的接口
具体观察者(ConcreteObserver):具体观察者实现了观察者Observer接口,并注册具体主题,以便接收更新。
观察者模式提供了一种对象设计,让主题和观察者之间松耦合,当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节,主题只知道观察者实现了Observer接口,不需要知道观察者的具体类是谁,做了些什么其他的细节。
通过ConcreteObserver注册两个观察者ConcreteObserverA和ConcreteObserverB,一旦被观察者有更新,两个观察者会立刻收到更新通知。具体代码如下:
声明Subject主题接口,Subject.java:
public interface Subject { void registerObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers();}
声明ConcreteObserver具体主题,NetConcreteSubject.java:
public class NetConcreteSubject implements Subject { private Listobservers; private ObserverBean bean; public NetConcreteSubject() { observers = new ArrayList<>(); } @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { int pos = observers.indexOf(observer); if (pos > 0) { observers.remove(pos); } } @Override public void notifyObservers() { if (bean == null) return; for (int i = 0; i < observers.size(); i++) { Observer observer = observers.get(i); observer.update(bean); } } public void setStatusChanged(ObserverBean bean) { this.bean = bean; notifyObservers(); }}
声明观察者接口, Observer.java:
public interface Observer { void update(Object obj);}
声明具体观察者类,ConcreteObserverA.java:
public class ConcreteObserverA implements Observer { @Override public void update(Object obj) { if (obj instanceof ObserverBean) { ObserverBean bean = (ObserverBean) obj; System.out.print("ConcreteObserverA 网络类型:" + bean.netType + ",网络状态:" + bean.netStatus + "\n"); } }}
ConcreteObserverB.java:
public class ConcreteObserverB implements Observer { @Override public void update(Object obj) { if (obj instanceof ObserverBean) { ObserverBean bean = (ObserverBean) obj; System.out.print("ConcreteObserverB 网络类型:" + bean.netType + ",网络状态:" + bean.netStatus + "\n"); } }}
调用过程:
public static void main(String[] args) { //初始化主题(被观察者) NetConcreteSubject subject = new NetConcreteSubject(); //初始化观察者A ConcreteObserverA observerA = new ConcreteObserverA(); //初始化观察者B ConcreteObserverB observerB = new ConcreteObserverB(); //注册观察者A subject.registerObserver(observerA); //注册观察者B subject.registerObserver(observerB); //通知所有观察者数据有更新 ObserverBean bean = new ObserverBean("wifi", "有网"); subject.setStatusChanged(bean); }
运行结果:
ConcreteObserverA 网络类型:wifi,网络状态:有网ConcreteObserverB 网络类型:wifi,网络状态:有网
Observable.java:
/** * Java学习交流QQ群:589809992 我们一起学Java! */public class Observable { private boolean changed = false; private Vectorobs = new Vector(); public Observable() { } public synchronized void addObserver(Observer var1) { if(var1 == null) { throw new NullPointerException(); } else { if(!this.obs.contains(var1)) { this.obs.addElement(var1); } } } public synchronized void deleteObserver(Observer var1) { this.obs.removeElement(var1); } public void notifyObservers() { this.notifyObservers((Object)null); } public void notifyObservers(Object var1) { Object[] var2; synchronized(this) { if(!this.changed) { return; } var2 = this.obs.toArray(); this.clearChanged(); } for(int var3 = var2.length - 1; var3 >= 0; --var3) { ((Observer)var2[var3]).update(this, var1); } } public synchronized void deleteObservers() { this.obs.removeAllElements(); } protected synchronized void setChanged() { this.changed = true; } protected synchronized void clearChanged() { this.changed = false; } public synchronized boolean hasChanged() { return this.changed; } public synchronized int countObservers() { return this.obs.size(); }}
Observer.java:
public interface Observer { void update(Observable var1, Object var2);}
上面的Observer和Observable类都位于java.util目录中,是JDK中已经写好的,那么我们可以直接拿来用了:
主题类NetSubject.java:
public class NetSubject extends Observable { public void setNetChanged(ObserverBean bean){ setChanged(); notifyObservers(bean); }}
观察者SystemObserverA.java:
public class SystemObserverA implements Observer { @Override public void update(Observable observable, Object o) { if (o instanceof ObserverBean && observable instanceof NetSubject) { ObserverBean bean = (ObserverBean) o; System.out.print("ConcreteObserverA 网络类型:" + bean.netType + ",网络状态:" + bean.netStatus + "\n"); } }}
观察者SystemObserverB.java:
/** * Java学习交流QQ群:589809992 我们一起学Java! */public class SystemObserverB implements Observer { @Override public void update(Observable observable, Object o) { if (o instanceof ObserverBean && observable instanceof NetSubject) { ObserverBean bean = (ObserverBean) o; System.out.print("ConcreteObserverB 网络类型:" + bean.netType + ",网络状态:" + bean.netStatus + "\n"); } }}
执行程序:
//初始化主题(被观察者) NetSubject subject = new NetSubject(); //初始化观察者A SystemObserverA observerA = new SystemObserverA(); //初始化观察者B SystemObserverB observerB = new SystemObserverB(); //注册观察者A subject.addObserver(observerA); //注册观察者B subject.addObserver(observerB); //通知观察者有更新 ObserverBean bean = new ObserverBean("4G流量", "有网"); subject.setNetChanged(bean);
运行结果:
ConcreteObserverB 网络类型:4G流量,网络状态:有网ConcreteObserverA 网络类型:4G流量,网络状态:有网
注意:
当使用JDK内置观察者模式时,当需要通知观察者更新数据时,首先需要调用setChanged()来改变状态,否则观察者不会收到任何更新通知。为什么会这样呢,来看下JDK中的源码就知道了:private boolean changed = false; protected synchronized void setChanged() { this.changed = true; } public void notifyObservers(Object var1) { Object[] var2; synchronized(this) { //如果changed为false,将直接返回 if(!this.changed) { return; } var2 = this.obs.toArray(); this.clearChanged(); } for(int var3 = var2.length - 1; var3 >= 0; --var3) { ((Observer)var2[var3]).update(this, var1); } }
通过setChanged()将changed设置为true,否则当调用notifyObservers(Object var1)将没有任何作用。
使用JDK内置观察者模式看似程序更简单了,但缺点也暴露出来了:
1、Observable是一个类,而不是一个接口,导致Observable类的扩展性不高,限制了它的使用和复用。 2、Observable将某些方法保护了起来(setChanged()和clearChanged()为protected),这意味着除非继承自Observable,否则将有关键的方法不能调用。导致无法通过组合的方式使其它类获得Observable类的功能所以,如果JDK内置的观察者模式符合你的需求,那么可以尽情的使用内置的观察者模式,否则应该自己实现一套观察者模式。
转载地址:http://xvrbi.baihongyu.com/