1. 程式人生 > >(六)觀察者模式詳解(包含觀察者模式JDK的漏洞以及事件驅動模型)

(六)觀察者模式詳解(包含觀察者模式JDK的漏洞以及事件驅動模型)

複製程式碼
import java.util.Vector;

//被觀察者類
public class Observable {
    //這是一個改變標識,來標記該被觀察者有沒有改變
    private boolean changed = false;
    //持有一個觀察者列表
    private Vector obs;
    
    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); } //notifyObservers(Object arg)的過載方法 public void notifyObservers() { notifyObservers(
null); } //通知所有觀察者,被觀察者改變了,你可以執行你的update方法了。 public void notifyObservers(Object arg) { //一個臨時的陣列,用於併發訪問被觀察者時,留住觀察者列表的當前狀態,這種處理方式其實也算是一種設計模式,即備忘錄模式。 Object[] arrLocal; //注意這個同步塊,它表示在獲取觀察者列表時,該物件是被鎖定的 //也就是說,在我獲取到觀察者列表之前,不允許其他執行緒改變觀察者列表 synchronized (this) { //如果沒變化直接返回
if (!changed) return; //這裡將當前的觀察者列表放入臨時陣列 arrLocal = obs.toArray(); //將改變標識重新置回未改變 clearChanged(); } //注意這個for迴圈沒有在同步塊,此時已經釋放了被觀察者的鎖,其他執行緒可以改變觀察者列表 //但是這並不影響我們當前進行的操作,因為我們已經將觀察者列表複製到臨時陣列 //在通知時我們只通知陣列中的觀察者,當前刪除和新增觀察者,都不會影響我們通知的物件 for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } //刪除所有觀察者 public synchronized void deleteObservers() { obs.removeAllElements(); } //標識被觀察者被改變過了 protected synchronized void setChanged() { changed = true; } //標識被觀察者沒改變 protected synchronized void clearChanged() { changed = false; } //返回被觀察者是否改變 public synchronized boolean hasChanged() { return changed; } //返回觀察者數量 public synchronized int countObservers() { return obs.size(); } }
複製程式碼