Head First- 觀察者模式(Obserber Pattern)

 觀察者模式(Obserber Pattern):定義對象之間一對多的依賴,當一個對象改變狀態時,它的所有依賴者都會收到通知並自動更新。

    觀察者模式主要用來處理一對多的數據更新和傳輸的關係。易於對實現對象的控制和更新。觀察者模式主要分爲兩部分,一部分稱爲主題(Subject)類似於報紙的出版商,另一部分稱爲觀察者(Observer)類似於報紙的訂購者。這個模式就相當於出版商和訂購者的關係,當訂購者需要得到數據時就會在出版商這裏註冊,以通知出版商,取得獲取數據的資格,一旦有數據更新的時候訂購者就像讀報紙一樣得到數據,這樣報社不需要去照顧訂購者的數量和實現方法。只需要對已註冊的跟新即可。

    舉個例子

    接到一個項目,用來做氣象監測,分爲兩個部分,一個是WeatherData對象:追蹤監測的氣象數據,並跟新佈告板。另一個是佈告板:通過終端(手機、電視、電腦)顯示當前天氣狀況給用戶。

    分析需求:

      已知:1WeatherData類有三個get方法,取得三個測量值:溫度、溼度和氣壓。

            2)有一個update方法。

            3)一旦WeatherData有新的數據產生時,就會立即向佈告板更新。

            4)需要可擴展,因爲終端不同,需要能讓其他開發人員建立佈告板。

    這樣就可以來設計了,通過上面對觀察者的介紹和針對接口的OO原則。

       定義主題接口:

//主題接口
public interface Subject{
    //註冊觀察者方法
    public void registerObserver(Observer ob);
    //刪除觀察者方法
    public void removeObserver(Observer ob);
    //通知觀察者方法
    public void notifyObserver(Observer ob);
}

觀察者接口:

//觀察者接口
public interface Observer{
    //
更新數據方法
    public void update(float temp,float humidity,float pressure);
}

發佈接口:

//發佈接口
public interface DisplayElement{
    public void display();
}

 

開始實現:

         首先實現WeatherData
//通過Subject接口實現WeatherData
public class WeatherData implements Subject{
    //定義一個列表,用來盛放註冊的觀察者
    private ArrayList observers;
 
    private float temperature;
    private float humidity;
    private float pressure;
 
    public WeatherData(){
        observers=new ArrayList();
    }
 
    public void registerObserver(Observer ob){
        observers.add(ob);
    }
    public void removeObserver(Observer ob){
        //返回此列表中首次出現的ob的索引,如果此列表不包含元素,則返回 -1。
        if(observers.indexOf(ob)>=0)
            observers.remove(ob);
    }
    public void notifyObserver(Observer ob){
        for(int i=0;i<observers.size();i++){
            Observer observer=(Observer)    observers.get(i);
            observer.update(temperature,humidity,pressure);
        }
    }
    //當WeatherData數據改變時,纔會更新。
    public void measurementsChanged(){
        notifyObserver();
    }

    public void setMeasurements(float temperature,float humidity,float pressure){
        this.temperature=temperature;
        this.humidity=humidity;
        this.pressure=pressure;
 
        measurementsChanged();
    }
}
}

通過Observer實現佈告板:

//通過Observer接口實佈告板
public class BillBoard implements Observer,DisplayElement(){
    private float temperature;
    private float humidity;
    private float pressure;
 
    public BillBoard(Subject WeatherData){
        this.WeatherData=WeatherData;
        WeatherData.removeObserver(this);
    }
    public void update(float temperature,float humidity,float pressure){
        this.temperature=temperature;
        this.humidity=humidity;
        this.pressure=pressure;
 
        display();
    }


    /*
        
這個方法由開發人員重寫
    */

    @Override
    public void display(){
    }
 
}

這樣整個設計基本上就OK了,下面寫個test類來測試一下:

//測試類
public class test{
    public static void main(String args[]){
        WeatherData watherData=new WeatherData();
 
        BillBoard billBoard=new BillBoard();

//不止這一個公告板,如果有的話在下面繼續加
 
        weatherData.setMeasurements(22,55,66);
        weatherData.setMeasurements(5,96,47);
    }
 
}

    不出錯的話這個任務基本上就完成了。

到目前爲止,已經從無到有的完成了Observer Pattern。關於觀察者,主題只知道觀察者實現的Observer接口,不需要知道其他的任何細節。  任何時候都可以增加新的觀察者,只需要在主題ArrayList裏面註冊就可以。   有新的類型觀察者出現時,主題代碼還是不需要修改,主題代碼不在乎別的,只有一個功能就是給已註冊的觀察者發送數據。   獨立的複用主題或者觀察者,二者獨立,只需要遵守接口,改變不會產生影響。

    多說一點,上面的這種設計實際上是由主題進行一個類似於“推”的動作,它把數據推送到各個觀察者。觀察者是被動接收數據的對象。實際上Java有一個內置的觀察者模式,實現的是另一種不同的思路。說白了是“拉”,觀察者從主題裏去拉取自己需要的數據,去按照自己的需求主動獲取數據。位於java.util包裏。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章