JAVA提供的對觀察者模式的支援(觀察者模式)
在JAVA語言的java.util庫裡面,提供了一個Observable類以及一個Observer介面,構成JAVA語言對觀察者模式的支援。
Observer介面
這個介面只定義了一個方法,即update()方法,當被觀察者物件的狀態發生變化時,被觀察者物件的notifyObservers()方法就會呼叫這一方法。
public interface Observer {
//第一引數是被觀察者(主題)物件,第二個引數是方法所需要的引數
void update(Observable o, Object arg);
}
Observable類
被觀察者類都是java.util.Observable類
package com.hb.observable; 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); } } /** * 將一個觀察者從觀察者聚集上刪除 */ public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } public void notifyObservers() { notifyObservers(null); } /** * 如果本物件有變化(那時hasChanged 方法會返回true) 呼叫本方法通知所有登記的觀察者,即呼叫它們的update()方法 * 傳入this和arg作為引數 */ public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { //根據changed屬性判斷被觀察者(主題)是否改變 if (!changed) return; arrLocal = obs.toArray(); //標記觀察者沒有改變 clearChanged(); } for (int i = arrLocal.length - 1; i >= 0; i--) ((Observer) arrLocal[i]).update(this, arg); } /** * 將觀察者聚集清空 */ public synchronized void deleteObservers() { obs.removeAllElements(); } /** * 將“已變化”設定為true */ protected synchronized void setChanged() { changed = true; } /** * 將“已變化”重置為false */ protected synchronized void clearChanged() { changed = false; } /** * 檢測本物件是否已變化 */ public synchronized boolean hasChanged() { return changed; } /** * Returns the number of observers of this <tt>Observable</tt> object. * @return the number of observers of this object. */ public synchronized int countObservers() { return obs.size(); } }
這個類代表一個被觀察者物件,有時稱之為主題物件。一個被觀察者物件可以有數個觀察者物件,每個觀察者物件都是實現Observer介面的物件。在被觀察者發生變化時,會呼叫Observable的notifyObservers()方法,此方法呼叫所有的具體觀察者的update()方法,從而使所有的觀察者都被通知更新自己。
怎樣使用JAVA對觀察者模式的支援
這裡給出一個非常簡單的例子,說明怎樣使用JAVA所提供的對觀察者模式的支援。在這個例子中,被觀察物件叫做Watched;而觀察者物件叫做Watcher。Watched物件繼承自java.util.Observable類;而Watcher物件實現了java.util.Observer介面。另外有一個Test類扮演客戶端角色。
被觀察者Watched類原始碼
public class Watched extends Observable{
private String data = "";
public String getData() {
return data;
}
public void setData(String data) {
if(!this.data.equals(data)){
this.data = data;
setChanged();
}
notifyObservers();
}
}
觀察者類原始碼
public class Watcher implements Observer{
public Watcher(Observable o){
o.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
System.out.println("狀態發生改變:" + ((Watched)o).getData());
}
}
測試類原始碼
public class Test {
public static void main(String[] args) {
//建立被觀察者物件
Watched watched = new Watched();
//建立觀察者物件,並將被觀察者物件登記
Observer watcher = new Watcher(watched);
//給被觀察者狀態賦值
watched.setData("start");
watched.setData("run");
watched.setData("stop");
}
}
Test物件首先建立了Watched和Watcher物件。在建立Watcher物件時,將Watched物件作為引數傳入;然後Test物件呼叫Watched物件的setData()方法,觸發Watched物件的內部狀態變化;Watched物件進而通知實現登記過的Watcher物件,也就是呼叫它的update()方法