設計模式 | 觀察者模式

觀察者模式

傳統方法:
/**
 * @author 孫一鳴 on 2020/2/18
 *
 * 包含最新的天氣信息
 */
public class WeatherData {
    private float temperatrue;
    private float pressure;
    private float humidity;
    private CurrentConditions currentConditions;

    public WeatherData(CurrentConditions currentConditions) {
        this.currentConditions = currentConditions;
    }

    public float getTemperature() {
        return temperatrue;
    }

    public float getPressure() {
        return pressure;
    }

    public float getHumidity() {
        return humidity;
    }

    public void dataChange() {
    	//數據改變時,調用第三方的方法,通知第三方
        currentConditions.update(getTemperature(), getPressure(), getHumidity());
    }

    //數據更新
    public void setData(float temperature, float pressure, float humidity) {
        this.temperatrue = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        dataChange();
    }
}
第三方使用數據網站
/**
 * @author 孫一鳴 on 2020/2/18
 */
public class CurrentConditions {
    //溫度 氣壓 溼度
    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 + "***");
    }
}
測試:
/**
 * @author 孫一鳴 on 2020/2/18
 */
public class Client {
    public static void main(String[] args) {
        CurrentConditions currentConditions = new CurrentConditions();
        WeatherData weatherData = new WeatherData(currentConditions);
        weatherData.setData(30, 150, 40);
    }

}

在這裏插入圖片描述

分析:
如果此時,百度網站也想要獲得天氣數據,我們該怎麼改呢?
1.創建觀察數據者 百度網站
2.更改目標數據WeatherData
違反ocp原則,
//在WeatherData中,當增加一個第三方,都需要創建一個對應的第三方的公告板對象,並加入到dataChange, 不利於維護,也不是動態加入

public void dataChange() {
currentConditions.update(getTemperature(), getPressure(), getHumidity());
}

觀察者模式:

 觀察者模式類似訂牛奶業務

  1. 奶站/氣象局:Subject
  2. 用戶/第三方網站:Observer

Subject:登記註冊、移除和通知
1) registerObserver 註冊
2) removeObserver 移除
3) notifyObservers() 通知所有的註冊的用戶,根據不同需求,可以是更新數據,讓用戶來取,也可能是實施推送,看具體需求定

Observer:接收輸入
update()

 觀察者模式:對象之間多對一依賴的一種設計方案,被依賴的對象爲Subject,依賴的對象爲Observer,Subject通知Observer變化,比如這裏的奶站是Subject,是1的一方。用戶時Observer,是多的一方。

類圖:

在這裏插入圖片描述
觀察者模式結構中通常包括觀察目標觀察者兩個繼承層次結構

目標: Subject 接口:

/**
 * @author 孫一鳴 on 2020/2/18
 * 接口,讓WeatherData 來實現
 */
public interface Subject {
    public void registerObserver(MyObserver o);
    public void removeObserver(MyObserver o);
    public void notifyObserver();

}

觀察者: Observer 接口:

/**
 * 觀察者接口
 * @author 孫一鳴 on 2020/2/18
 */
public interface MyObserver {
    public void update(float temperature , float pressure ,float humidity);
}

觀察者: Observer 實現 : 百度網站要獲得天氣信心 :


/**
 * @author 孫一鳴 on 2020/2/18
 */
public class BaiDuCurrentConditions   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 + "***");
    }
}

目標: subject實現 : 氣象中心發佈信息:

/**
 * @author 孫一鳴 on 2020/2/18
 * <p>
 * 包含最新的天氣信息
 * 使用ArrayList 管理觀察者
 * 當數據更新時 主動遍歷ArrayList 通知觀察者 更改最新信息
 */
public class WeatherData implements Subject {
    private float temperature;
    private float pressure;
    private float humidity;
    //private CurrentConditions currentConditions;

    //觀察者集合
    private ArrayList<MyObserver> observers;
    public WeatherData() {
        observers = new ArrayList<>();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getPressure() {
        return pressure;
    }

    public float getHumidity() {
        return humidity;
    }

    public void dataChange() {
        notifyObserver();
    }

    //數據更新
    public void setData(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        dataChange();
    }
    @Override
    public void registerObserver(MyObserver o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(MyObserver o) {
        observers.remove(o);
    }

    @Override
    public void notifyObserver() {
        for (int i = 0; i <observers.size() ; i++) {
            observers.get(i).update(this.temperature,this.pressure,this.humidity);
        }
    }
}
觀察者模式測試:
/**
 * @author 孫一鳴 on 2020/2/18
 */
public class Client {
    public static void main(String[] args) {

        //創建目標
        WeatherData weatherData  = new WeatherData();

        //創建觀察者
        CurrentConditions currentConditions = new CurrentConditions();

        //註冊觀察者
        weatherData.registerObserver(currentConditions);

        //測試
        weatherData.setData(100, 100, 40);
    }

}

在這裏插入圖片描述

觀察者模式的好處
  1. 觀察者模式設計後,會以集合的方式來管理用戶(Observer),包括註冊,移除
    和通知。
  2. 這樣,我們增加觀察者(這裏可以理解成一個新的公告板),就不需要去修改核
    心類WeatherData不會修改代碼,遵守了ocp原則。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章