观察者模式是Java非常重要的一个设计模式。对于观察者模式,JDK已经为我们提供了对应的接口和类。
分别是观察者Observer,观察者也成为订阅者Subscribe,
JDK代码为:
package java.util;
/**
* A class can implement the <code>Observer</code> interface when it
* wants to be informed of changes in observable objects.
*
* @author Chris Warth
* @see java.util.Observable
* @since JDK1.0
*/
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
Observer是一个接口,只是一个方法update用于接收通知者的通知并做出相应,具体的逻辑肯定是需要开发者自己实现的了。
被观察者(或通知者(Publish,发布者)),JDK的源码如下:
package java.util; public class Observable { private boolean changed = false;
private Vector obs; /** Construct an Observable with zero Observers. */ public Observable() { obs = new Vector(); } /** * 添加一个观察者(订阅者),已经存在则不再重复添加 * 支持多线程*/ public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } /** * 删除一个观察者(订阅者Subscribe) * 支持多线程*/ public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } /** * 通知观察者(订阅者Subscribe)*/ public void notifyObservers() { notifyObservers(null); } /** * 通知观察者(订阅者Subscribe),带参数*/ 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); } /** * 删除所有观察者(订阅者Subscribe) */ public synchronized void deleteObservers() { obs.removeAllElements(); } /** * 设置变更 */ protected synchronized void setChanged() { changed = true; } /** * 清除变更*/ protected synchronized void clearChanged() { changed = false; } /** * 获取变更标识
*/ public synchronized boolean hasChanged() { return changed; } /** * 获得观察者数(订阅者数Subscribe)*/ public synchronized int countObservers() { return obs.size(); } }
Java源码考虑比较周到的。首先,使用Vector,Vector相比于ArrayList来说,它是线程安全的。其次,在添加和删除观察者时对两个方法使用了synchronized关键字,
这都是在为多线程考虑。确实Java源码并不是那么可怕,它同样也是由一些最简单最基础的组合而来。
下面看两个实例
实例一
NumObserable是一个被观察者,当它的成员变量data的数值发生变化时,会通知所有的观察者。
NumObserable.java
/** * 被观察者*/ public class NumObservable extends Observable { private int data = 0; public int getData() { return data; } public void setData(int i) { data = i; setChanged(); notifyObservers(); } }
NumObserver是观察者。当它的被观察者(NumObserable)执行了notifyObservers()后,它会执行uodate()方法。
NumObserver.java
public class NumObserver implements Observer { @Override public void update(Observable o, Object arg) { NumsObservable myObserable = (NumsObservable) o; System.out.println("Data has changed to " + myObserable.getData()); } }
测试类SingleTest,在这里将观察者加入到被观察者的观察列表中。
SingleTest.java
public class SingleTest { /** * @param args */ public static void main(String[] args) { NumObservable number = new NumObservable(); number.addObserver(new NumObserver()); number.setData(1); number.setData(2); number.setData(3); } }
结果:
Data has changed to 1
Data has changed to 2
Data has changed to 3
实例二
这个实例中,还是对data进行观察,拥有两个观察者,分别观察奇数和偶数的变化,通过notifyObservers(arg)中的参数arg来识别通知信息。
被观察者NumsObservable.java
public class NumsObservable extends Observable { public final static Integer ODD = 1; public final static Integer EVEN = 2; private int data = 0; public int getData() { return data; } public void setData(int i) { data = i; Integer flag = EVEN; if ((data & 0x0001) == 1) flag = ODD; setChanged(); notifyObservers(flag); } }
奇数观察者OddObserver.java
public class OddObserver implements Observer { @Override public void update(Observable o, Object arg) { if (arg == NumsObservable.ODD) { NumsObservable myObserable = (NumsObservable) o; System.out.println("OddObserver:Data has changed to " + myObserable.getData()); } } }
偶数观察者EvenObserver.java
public class EvenObserver implements Observer { @Override public void update(Observable o, Object arg) { if (arg == NumsObservable.EVEN) { NumsObservable myObserable = (NumsObservable) o; System.out.println("EvenObserver:Data has changed to " + myObserable.getData()); } } }
测试类MultiTest.java
public class MultiTest { /** * @param args */ public static void main(String[] args) { NumsObservable number = new NumsObservable(); number.addObserver(new OddObserver()); number.addObserver(new EvenObserver()); number.setData(1); number.setData(2); number.setData(3); } }
结果:
OddObserver:Data has changed to 1
EvenObserver:Data has changed to 2
OddObserver:Data has changed to 3