1. 程式人生 > >設計模式真香筆記-觀察者模式

設計模式真香筆記-觀察者模式

觀察者模式的介紹

觀察者模式:物件之間一對多依賴,當一個物件改變狀態的時候,它的所有依賴都會收到通知並且自動更新。
這樣說可能有些人不能理解,我們來舉個生動形象的例子:

許多人以前會經常訂閱雜誌,雜誌社會定期發雜誌給訂閱者,當然他也可以取消訂閱,那麼雜誌社就不會繼續發雜誌給訂閱者。

這個例子裡面雜誌社就是可觀察者,而訂閱者就相當於觀察者,雜誌社定期更新會通知他的所有依賴也就是訂閱者。
再來個圖促進理解:
觀察者模式

利用到的新原則

  • 為互動物件之間的鬆耦合設計而努力

觀察者模式的例子(氣象臺佈告板例子)

UML類圖

有空在畫圖。

實現程式碼附帶一些解釋

  • Subject介面
/**
 * Subject介面為可觀察者(主題)介面
 * @
 */
public interface Subject {
     /**
      * @param o 傳入引數為觀察者介面實現物件
      */
     void registerObserver(Observer o);//註冊為觀察者
     void removeObserver(Observer o);//退出觀察者
     void notifyObserevers();//當主題資料改變時及時候通知觀察者。
}
  • Observer介面
public interface Observer {//觀察者介面
    void update(float temperature, float humidity,float pressure);//更新資料
}

  • display介面
public interface Display {//顯示資料
    void display();
}

  • WeatherData(實現可觀察介面成為可觀察者)
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 notifyObserevers() { for (Object observer: observers ) { Observer observer1 = (Observer) observer; observer1.update(temperature,humidity,pressure); } } public void measurementsChanged(){//更新通知 notifyObserevers(); } public void setMeasurements(float temperature, float humidity, float pressure) {//改變觀察者資料 this.temperature=temperature; this.humidity=humidity; this.pressure=pressure; measurementsChanged(); } //其他擴充套件方法 }
  • CurrentConditionDisplay (實現觀察者介面成為觀察者)
public class CurrentConditionDisplay implements  Observer,Display {
    private float temperature;
    private float humidity;
    private Subject weatherData;
    public CurrentConditionDisplay(Subject weatherData){//構造方法實現註冊為觀察者
        this.weatherData=weatherData;
        weatherData.registerObserver(this);
    }

    @Override
    public void display() {//顯示資料
        System.out.println("CurrentConditionDisplay:"+temperature+"Humidity"+humidity);
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
            this.temperature=temperature;
            this.humidity=humidity;
            display();
    }
}
  • CurrentConditionDisplayM(實現觀察者介面成為觀察者)
public class CurrentConditionDisplayM implements  Observer,Display {
    private float temperature;
    private float humidity;
    private float pressure;
    private Subject weatherData;
    public CurrentConditionDisplayM(Subject weatherData){
        this.weatherData=weatherData;
        weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("CurrentConditionDisplayM:"+temperature*3+"Humidity"+humidity/2+"pressure"+pressure*4);
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature=temperature;
        this.humidity=humidity;
        this.pressure=pressure;
        display();
    }
}
  • WeatherStation(氣象站類也就是測試類)
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
       CurrentConditionDisplay currentConditionDisplay = new CurrentConditionDisplay(weatherData);
        CurrentConditionDisplayM currentConditionDisplayM = new CurrentConditionDisplayM(weatherData);
        weatherData.setMeasurements(80,68,29.2f);
       weatherData.setMeasurements(90,100,23);

    }
}
  • 列印結果
    觀察者模式列印結果

觀察者模式的總結

可觀察者和觀察者之間用鬆耦合的形式結合,可觀察者只知道觀察者實現了觀察者的介面,而不知道觀察者具體內容。
有多個觀察者時候,不可以依賴特定的通知次序。
swing類庫中就有很多使用觀察者模式的例子,譬如說:點選按鈕新增多種監聽器,實現不同的功能。

一些補充

在java.util 類庫中有實現好的觀察者模式。Observable.java(可觀察者類是類不是介面),在這類裡面有一個setchanged()方法用來標記可觀察者的狀態的事實,那他的意義是什麼呢?我們不需要標記就可以更新啊,其實他的作用是為了控制可觀察者的更新頻率,我們可以通過這個方法實現上面的氣象站例子 三天,或者半個月更新一次,沒有這個方法,我們沒有辦法控制,氣象站就會實時更新。具體我們可以java.util類庫中Observable.java的原始碼。


本文參考:《Head First 設計模式》