觀察者模式 —— java.util.Observable + java.util.Observer 源碼學習

學習觀察者模式,結合JavaJDK的內置觀察者模式代碼一塊兒學習package java.util;java


//不是抽象類,也不是接口
public class Observable { private boolean changed = false; //狀態標誌 private Vector<Observer> 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); } /**/ public void notifyObservers() { notifyObservers(null); } /*向全部註冊的觀察者發送更新通知,參數是更新的信息
  
*/ public void notifyObservers(Object arg) { /* * .一個臨時的數組緩存,用於當前被觀察者(集合)的狀態的一個快照 */ Object[] arrLocal; synchronized (this) {
      /*從集合中提取每一個觀察者的代碼須要同步,可是通知觀察者的代碼不須要(不該該)。
        潛在的最壞的結果是:
        (1)新增的觀察者錯過了正在進行的通知
        (2)未註冊的觀察者被通知到了
     */
            if (!changed) //判斷標誌 return; arrLocal = obs.toArray(); //集合轉化成數組 clearChanged(); //標誌恢復成false 不須要通知更新 } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); //每一個觀察者的update方法須要的參數是兩個,主題和參數 } /** * 清除所有的觀察者 */
    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; } /*返回觀察者的數量*/
    public synchronized int countObservers() { return obs.size(); } }

 

這個類的主要構成要點:數組

一、包含全部觀察者的(空)的集合 + 對這個集合的管理操做(增減,查看數量)緩存

二、包含一個(是否變更)標誌 + 對這個標誌的管理操做(設置、查看)ide

三、向全部觀察者發送通知函數

 

 

繼續學習觀察者模式,JavaJDK中java.util.Observer源碼學習:學習

package java.util;

/*這是觀察者的接口,關鍵點就是它有一個update方法,每當被通知修改時候,就是這個方法被調用
 */
public interface Observer {
    void update(Observable o, Object arg);
}

 

使用這兩個內置的觀察者模式類,參考方法:測試

(1)新建一個具體主題類繼承Observable,  不須要重寫它的任何方法,只要添加本身須要的業務邏輯: 設置傳遞的參數信息,發送消息的方法……this

  惟一須要注意的是:兩種通知方式,參數的獲取方法不一樣spa

public class ConcreteSubjectA extends Observable {
    //保存數據
    private String name;

    //設置參數信息
    public void setInfo(String a){
        this.name=a;
    }

    //觸發更新
    public void sendNotify(){
        setChanged(); //必須先要設置一下標誌,告知已經改了
        //通知方式一;讓觀察者本身按需拉取(因此傳參是空)
        notifyObservers();
        //通知方式二:直接把信息所有推送
        notifyObservers(name);
    }
    
    //若是是拉取的通知方式,還要給出參數的獲取方法
    public String getName() {
        return name;
    }
}

(2) 新建觀察者類,實現Observer接口,這裏一般是有主題的引用的,這樣能夠本身完成註冊,註銷,和取數據設計

public class FirstObserver implements Observer {
    private Observable observable;

    public FirstObserver(Observable observable) {
        this.observable = observable;
        observable.addObserver(this);// 在構造的時候就能夠把本身註冊了,不用手動添加了,若是是改造已經存在的實體類,仍是須要手動添加
    }

    @Override
    public void update(Observable o, Object arg) {
        if(o instanceof ConcreteSubjectA){
            String name = ((ConcreteSubjectA) o).getName(); //拉取的通知方式,arg是null. 要本身獲取
            //具體更新操做…… 略……
        }
    }
}

測試類:

public class Test {
    public static void main(String[] args) {
        ConcreteSubjectA ca=new ConcreteSubjectA();
        FirstObserver firstObserver = new FirstObserver(ca); //構造時候註冊
        ca.setInfo("我是新名字1");
        ca.sendNotify(); //本身寫的通知方法,不是父類的notify
        ca.setInfo("我是新名字2");
        ca.sendNotify();
        ca.setInfo("我是新名字3");
        ca.sendNotify();
    }
}
/*
運行後輸出:
已經更新啦……我是新名字1
已經更新啦……我是新名字2
已經更新啦……我是新名字3
 */

 

java.util.Observable存在的問題:

一、它是一個類,而不是一個接口,限制了它的複用。 想要用它就必須繼承它,那就不能再繼承其它類。

二、setChanged() 等方法是被保護的,除了繼承,沒法使用它。違反「多用組合,少用繼承」的設計原則。

相關文章
相關標籤/搜索