1. 程式人生 > 實用技巧 >設計模式之觀察者模式

設計模式之觀察者模式

天氣預報專案需求,具體要求如下:

1.氣象站可以將每天測量到的溫度,溼度,氣壓等等以公告的形式釋出出去(比如釋出到第三方)

2.需要設計開放型API,便於其他第三方也能接入氣象站獲取資料。

3.提供溫度、氣壓、和溼度的介面。

4.測量資料更新時,要能實時的通知給第三方

類圖:

程式碼如下:

//介面, 讓WeatherData 來實現
public interface Subject {

    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void
notifyObservers(); }

//觀察者介面,有觀察者來實現
public interface Observer {

    public void update(float temperature, float pressure, float humidity);
}
public class CurrentConditions implements Observer {

    // 溫度,氣壓,溼度
    private float temperature;
    private float pressure;
    private float humidity;

    
// 更新 天氣情況,是由 WeatherData 來呼叫,我使用推送模式 public void update(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; display(); } // 顯示 public void display() { System.out
.println("***Today mTemperature: " + temperature + "***"); System.out.println("***Today mPressure: " + pressure + "***"); System.out.println("***Today mHumidity: " + humidity + "***"); } }

public class BaiduSite implements Observer {

    // 溫度,氣壓,溼度
    private float temperature;
    private float pressure;
    private float humidity;

    // 更新 天氣情況,是由 WeatherData 來呼叫,我使用推送模式
    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }

    // 顯示
    public void display() {
        System.out.println("===百度網站====");
        System.out.println("***百度網站 氣溫 : " + temperature + "***");
        System.out.println("***百度網站 氣壓: " + pressure + "***");
        System.out.println("***百度網站 溼度: " + humidity + "***");
    }

}

/**
 * 類是核心
 * 1. 包含最新的天氣情況資訊
 * 2. 含有 觀察者集合,使用ArrayList管理
 * 3. 當資料有更新時,就主動的呼叫   ArrayList, 通知所有的(接入方)就看到最新的資訊
 * @author Administrator
 *
 */
public class WeatherData implements Subject {
    private float temperatrue;
    private float pressure;
    private float humidity;
    //觀察者集合
    private ArrayList<Observer> observers;

    //加入新的第三方

    public WeatherData() {
        observers = new ArrayList<Observer>();
    }

    public float getTemperature() {
        return temperatrue;
    }

    public float getPressure() {
        return pressure;
    }

    public float getHumidity() {
        return humidity;
    }

    public void dataChange() {
        //呼叫 接入方的 update

        notifyObservers();
    }

    //當資料有更新時,就呼叫 setData
    public void setData(float temperature, float pressure, float humidity) {
        this.temperatrue = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        //呼叫dataChange, 將最新的資訊 推送給 接入方 currentConditions
        dataChange();
    }

    //註冊一個觀察者
    @Override
    public void registerObserver(Observer o) {
        // TODO Auto-generated method stub
        observers.add(o);
    }

    //移除一個觀察者
    @Override
    public void removeObserver(Observer o) {
        // TODO Auto-generated method stub
        if(observers.contains(o)) {
            observers.remove(o);
        }
    }

    //遍歷所有的觀察者,並通知
    @Override
    public void notifyObservers() {
        // TODO Auto-generated method stub
        for(int i = 0; i < observers.size(); i++) {
            observers.get(i).update(this.temperatrue, this.pressure, this.humidity);
        }
    }
}

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //建立一個WeatherData
        WeatherData weatherData = new WeatherData();

        //建立觀察者
        CurrentConditions currentConditions = new CurrentConditions();
        BaiduSite baiduSite = new BaiduSite();

        //註冊到weatherData
        weatherData.registerObserver(currentConditions);
        weatherData.registerObserver(baiduSite);

        //測試
        System.out.println("通知各個註冊的觀察者, 看看資訊");
        weatherData.setData(10f, 100f, 30.3f);


        weatherData.removeObserver(currentConditions);
        //測試
        System.out.println();
        System.out.println("通知各個註冊的觀察者, 看看資訊");
        weatherData.setData(10f, 100f, 30.3f);
    }

}

列印結果:

通知各個註冊的觀察者, 看看資訊
***Today mTemperature: 10.0***
***Today mPressure: 100.0***
***Today mHumidity: 30.3***
===百度網站====
***百度網站 氣溫 : 10.0***
***百度網站 氣壓: 100.0***
***百度網站 溼度: 30.3***

通知各個註冊的觀察者, 看看資訊
===百度網站====
***百度網站 氣溫 : 10.0***
***百度網站 氣壓: 100.0***
***百度網站 溼度: 30.3***

Process finished with exit code 0


觀察者模式原理:

物件之間多對一依賴的一種設計方案,被依賴的物件為Subject,依賴的物件為Observer,Subject通知Observer變化,比如這裡的天氣就是Subject,是1的一方,使用者是Observer,是多的一方


觀察者模式的好處:

1.觀察者模式設計後,會以集合的方式來管理使用者(Observer),包括註冊,移除和通知。

2.我們增加觀察者後,就不需要去修改核心類WeatherDate不會修改程式碼,遵守了ocp原則


觀察者模式在jdk應用的原始碼分析

1.jdk的Observable類就使用了觀察者模式