1. 程式人生 > >JAVA提供的對觀察者模式的支援(觀察者模式)

JAVA提供的對觀察者模式的支援(觀察者模式)

  在JAVA語言的java.util庫裡面,提供了一個Observable類以及一個Observer介面,構成JAVA語言對觀察者模式的支援。

  Observer介面

  這個介面只定義了一個方法,即update()方法,當被觀察者物件的狀態發生變化時,被觀察者物件的notifyObservers()方法就會呼叫這一方法

public interface Observer {
//第一引數是被觀察者(主題)物件,第二個引數是方法所需要的引數
    void update(Observable o, Object arg);
}

Observable類

  被觀察者類都是java.util.Observable類

的子類。java.util.Observable提供公開的方法支援觀察者物件,這些方法中有兩個對Observable的子類非常重要:一個是setChanged(),另一個是notifyObservers()。第一方法setChanged()被呼叫之後會設定一個內部標記變數,代表被觀察者物件的狀態發生了變化。第二個是notifyObservers(),這個方法被呼叫時,會呼叫所有登記過的觀察者物件的update()方法,使這些觀察者物件可以更新自己。

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()方法