觀察者(Observer)模式

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

通俗來說:舉個報社(主題)和訂閱報紙的家庭(觀察者)例子。

  • 報社的業務就是出版報紙。

  • 向某家報社訂閱報紙,只要他們有新報紙出版,就會給你送來。只要你是他們的訂戶,你就會一直收到新報紙。

  • 當你不想再看報紙的時候,取消訂閱,他們就不會再送新報紙來。

  • 只要報社還在運營,就會一直有人(或單位)向他們訂閱報紙或取消訂閱報紙。

 

2、實現觀察者模式

   (1)包含Subject接口和Observer接口

   (2)Java內置的觀察者模式,在java.util包下包含最基本的Observer接口與Observable類。

3、包含Subject接口和Observer接口的代碼實現

       業務場景:系統中的三個部分是氣象站(獲取實際氣象數據的物理裝置)、WeatherData對 象(追蹤來自氣象站的數據,並   更新佈告板)和佈告板(顯示目前天氣狀況給用 戶看)。 我們的工作就是建立一個應用,利用WeatherData對象取得數據,並 更新佈告板:實時顯示目前天氣狀況。

      3.1、新建一個Sbuject主題接口

public interface Subject {
    // 註冊觀察者
    public void registerObserver(Observer o);
    // 刪除觀察者
    public void removeObserver(Observer o);
    // 當主題狀態改變時,通知所有觀察者
    public void notifyObservers();
}

    3.2   新建Observer觀察者接口

public interface Observer {
    public void update(float temp, float humidity, float preessure);
}

3.3   新建DisplayElement   ,佈告版顯示接口 

public interface DisplayElement {
    /*
    DisplayElement接口只包含了一個方法, 也就是display()。當佈告板需要顯示時, 調用此方法。
    */
    public void display();
}

3.4 創建具體的Subject類,實現Subject接口

public class WeatherData implements Subject {
    private ArrayList observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        observers = new ArrayList();
    }
    @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(i);
        }
    }

    @Override
    public void notifyObservers() {
        for(int i = 0; i < observers.size(); i++) {
            Observer observer = (Observer) observers.get(i);
            observer.update(temperature, humidity, pressure);
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

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

   3.5  創建具體的佈告板(Observer)類,實現Observer接口和display接口,可更新佈告板信息。

public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private float pressure;
    private Subject weatherData;

    public  CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }
    @Override
    public void display() {
        System.out.println("Current conditions: " + temperature + " degrees and " + humidity + "% humidity and "
                + pressure + "% pressure" );
    }

    @Override
    public void update(float temp, float humidity, float preessure) {
        this.temperature = temp;
        this.humidity = humidity;
        this.pressure = preessure;
        display();
    }
}

 3.6  最後,建立氣象站類,當天氣情況改變時候,看看輸出結果。

/**
 * @ClassName WeatherStation
 * @Description 更新天氣公告板
 * @Author 
 * @Date 2018/11/7 14:51
 */
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionDisplay = new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(50, 75, 43.4f);
    }
}

 輸出結果:

Current conditions: 80.0 degrees and 65.0% humidity and 30.4% pressure
Current conditions: 50.0 degrees and 75.0% humidity and 43.4% pressure

4、要點:

  • 觀察者模式定義了對象之間一對多的關係。 

  • 主題(也就是可觀察者)用一 個共同的接口來更新觀察者 。

  •  觀察者和可觀察者(主題)之間用鬆耦合方式結合(loosecoupling),可觀察者不知道觀察者的細節,只知道觀察者實現 了觀察者接口。 

  • 使用此模式時,你可從被觀察 者處推(push)或拉(pull) 數據(然而,推的方式被認爲 更“正確”)。 

  •  有多個觀察者時,不可以依賴特定的通知次序。 

  • Java有多種觀察者模式的實 現,包括了通用的java.util. Observable。 

  • 要注意java.util.Observable(是一個類實現上所帶來的一些問題)。 

  • 如果有必要的話,可以實現自 己的Observable,這並不難,不要害怕。 

  •  Swing大量使用觀察者模式, 許多GUI框架也是如此。 

  • 觀察者模式也被應用在許多地方, 例如:JavaBeans、RMI。

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