1. 程式人生 > >Head First 設計模式總結(二)觀察者模式

Head First 設計模式總結(二)觀察者模式

本文對《Head First 設計模式》中的觀察者模式進行了概括和總結

觀察者模式——在物件之間定義一對多的依賴,這樣一來,當一個物件改變狀態,依賴他的物件都會收到通知,並自動更新。

問題描述

要求公司建立一個 氣象資料站 (WeatherData物件),使之能從 氣象觀測站 (WeatherStation物件)獲取氣象資料(溫度temperature,溼度humidity,氣壓值pressure)。

並要求公司開發一個應用,使其包含三個天氣顯示板:目前狀況、氣象統計、天氣預測,這三個物件都獲取了來自WeatherData的三個氣象資料,但是對這些資料的處理方式不一樣。要求顯示板的顯示資料根據WeatherData傳過來的氣象資料實時變化。 下圖就是將氣象資料傳給了“目前狀況”這個展示板。 在這裡插入圖片描述

下面進入正題。

觀察者模式的思想

主題(Subject)+觀察者(Observer)=觀察者模式

在這裡插入圖片描述

下圖是Subject和Observer之間的關係 在這裡插入圖片描述 觀察者模式提供了一種物件設計,讓主題和觀察者之間鬆耦合。 關於觀察者的一切,主題只知道觀察者實現了某個介面(Observer介面),主題只需要知道這個觀察者 註冊與否 (是否需要定期向它提供訊息),如果註冊了,就定期傳送訊息給他。主題不需要知道觀察者本身具體是誰、做了什麼以及其他細節。

當新的觀察者註冊時,不用改主題程式碼,只需將通知的訊息給這個新來的觀察者發一份就行了,觀察者不在乎別的,它只會將相同訊息傳送給所有實現了Observer介面的具體觀察者物件,它一視同仁

以下是本例利用觀察者模式的結構圖

在這裡插入圖片描述 下面給出本例WeatherData類的實現程式碼

class WeatherData implements Subject {
    private float temperature;
    private float humidity;
    private float pressure;
    private ArrayList observers;
    public WeatherData(){
        List<Observer> observers = new ArrayList<Observer>();
    }
    @Override
    public void registerObserver(Observer o) {  //註冊為觀察者
            observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {  //登出,不再為觀察者
        int i = observers.indexOf(o);
        if(i>=0){
            observers.remove(o);
        }
    }
    @Override
    public void notifyObservers() {       //通知各個觀察者
        for(int i = 0;i<observers.size();i++){  //遍歷觀察者List,挨個呼叫每個觀察者的update()方法,實現通知
            Observer observer = (Observer) observers.get(i);
            observer.update(temperature,humidity,pressure);
        }
    }
    public void measurementsChanged(){
        notifyObservers();
    }
    public void setMeasurements(float temp,float humidity,float pressure){
        this.temperature = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
        WeatherStation.times++;
    }
}

以下是其中一個具體觀察者的程式碼實現:

class CurrentConditionDisplay implements Observer{
    private float temperature;
    private float humidity;
    private Subject weatherData;
    public CurrentConditionDisplay(Subject weatherData){  //通過觀察者的構造器將weatherData傳進來,並將該觀察者註冊
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
        //weatherData.removeObserver(this);
    }
    public void display() {
        System.out.println("current condition: "+temperature+"F degrees and"+humidity+"% humidity");
    }
    @Override
    public void update(float temp, float humidity, float pressure) { //該方法由weatherData的notifyObserver()方法觸發
        this.temperature = temp;
        this.humidity = humidity;
        display();
    }
}

總結

該設計模式的關鍵在於:如何將具體主題(WeatherData)和具體觀察者(Concret Observer)相互聯絡起來

解析:

1、觀察者們利用weatherData物件去註冊和登出

registerObserver()方法和removeObserver()方法都在weatherData物件中,因此具體觀察者的註冊必須通過weatherData物件來完成,但是是否註冊還是由具體觀察者它自己決定,所以得將weatherData物件傳到具體觀察者內部,顯然直接將weatherData物件傳入具體觀察者的構造器最直觀,因為當new出具體觀察者物件的時刻就能決定是否註冊為觀察者了。

2、weatherData利用觀察者們的物件才能呼叫它們的update()方法

由於有多個觀察者,因此可用一個Observer型別的List來存放註冊了的Observer,一旦某個Observer註冊成功,該觀察者的物件就傳到了List中,因此weatherData可以訪問所有註冊過的觀察者。這樣的目的在這裡很明確,一旦新資料到來,weatherData物件就呼叫notifyObserver()方法,進而利用List中的所有觀察者物件去呼叫它們各自的update()方法。

本設計模式中的一個設計原則是:為互動物件之間的鬆耦合而努力