1 天氣預報專案需求,具體要求如下:
1) 氣象站可以將每天測量到的溫度,溼度,氣壓等等以公告的形式釋出出去(比如釋出到自己的網站或第三方)。
2) 需要設計開放型 API,便於其他第三方也能接入氣象站獲取資料。
3) 提供溫度、氣壓和溼度的介面
4) 測量資料更新時,要能實時的通知給第三方
2 天氣預報設計方案 1-普通方案
WeatherData 類
- 傳統的設計方案
- 程式碼實現
package com.lin.observer; /** * 顯示當前天氣情況(可以理解為氣象站的網站) * @Description: * @author LinZM * @date 2021-2-7 12:49:27 * @version V1.8 */ public class CurrentConditions { // 溫度,氣壓,溼度 private float temperatrue; private float pressure; private float humidity; // 更新天氣情況 public void update(float temperature, float pressure, float humidity) { this.temperatrue = temperature; this.pressure = pressure; this.humidity = humidity; display(); } public void display(){ System.out.println("===Today's temperature: "+temperatrue+"==="); System.out.println("===Today's pressure: "+pressure+"==="); System.out.println("===Today's humidity: "+humidity+"==="); } }
package com.lin.observer; /* * 類是核心 1. 包含最新的天氣情況資訊 2. 含有 CurrentConditions 物件 3. 當資料有更新時,就主動的呼叫 * CurrentConditions 物件 update 方法(含 display), 這樣他們(接入方)就看到最新的資訊 */ 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() { //呼叫 接入方的 update currentConditions.update(getTemperature(), getPressure(), getHumidity()); } //當資料有更新時,就呼叫 setData public void setData(float temperature, float pressure, float humidity) { this.temperatrue = temperature; this.pressure = pressure; this.humidity = humidity; //呼叫 dataChange, 將最新的資訊 推送給 接入方 currentConditions dataChange(); } }
package com.lin.observer; public class Client { public static void main(String[] args) { CurrentConditions currentConditions = new CurrentConditions(); WeatherData weatherData = new WeatherData(currentConditions); weatherData.setData(10, 20, 3); } }
- 問題分析
1) 其他第三方接入氣象站獲取資料的問題
2) 無法在執行時動態的新增第三方 (新浪網站)
3) 違反 ocp 原則=>觀察者模式
//在 WeatherData 中,當增加一個第三方,都需要建立一個對應的第三方的公告板物件,並加入到 dataChange, 不利於維護,也不是動態加入
public void dataChange() {
currentConditions.update(getTemperature(), getPressure(), getHumidity());
}
3 觀察者模式原理
1) 觀察者模式類似訂牛奶業務
2) 奶站/氣象局:Subject
3) 使用者/第三方網站:Observer
- Subject:登記註冊、移除和通知
1) registerObserver 注 冊
2) removeObserver 移 除
3) notifyObservers() 通知所有的註冊的使用者,根據不同需求,可以是更新資料,讓使用者來取,也可能是實施推送, 看具體需求定
- Observer:接收輸入
- 觀察者模式:物件之間多對一依賴的一種設計方案,被依賴的物件為 Subject,依賴的物件為 Observer,Subject
通知 Observer 變化,比如這裡的奶站是 Subject,是 1 的一方。使用者時 Observer,是多的一方。
4 觀察者模式解決天氣預報需求
類圖說明
程式碼實現
package com.lin.observer.plus; public interface Subject { void registerObserver(Observer o); void removeObserver(Observer o); void notifyObserver(); }
package com.lin.observer.plus; import java.util.ArrayList; /* * 類是核心 1. 包含最新的天氣情況資訊 2. 含有 CurrentConditions 物件 3. 當資料有更新時,就主動的呼叫 * CurrentConditions 物件 update 方法(含 display), 這樣他們(接入方)就看到最新的資訊 */ 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 //currentConditions.update(getTemperature(), getPressure(), getHumidity()); notifyObserver(); } //當資料有更新時,就呼叫 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) { observers.add(o); } @Override public void removeObserver(Observer o) { if(observers.contains(o)) { observers.remove(o); } } @Override public void notifyObserver() { for (int i = 0; i < observers.size(); i++) { observers.get(i).update(temperatrue, pressure, humidity); } } }
package com.lin.observer.plus; public interface Observer { void update(float temperatrue, float pressure, float humidity); }
package com.lin.observer.plus; public class CurrentConditions implements Observer{ // 溫度,氣壓,溼度 private float temperatrue; private float pressure; private float humidity; // 更新天氣情況 public void update(float temperature, float pressure, float humidity) { this.temperatrue = temperature; this.pressure = pressure; this.humidity = humidity; display(); } public void display(){ System.out.println("===Today's temperature: "+temperatrue+"==="); System.out.println("===Today's pressure: "+pressure+"==="); System.out.println("===Today's humidity: "+humidity+"==="); } }
package com.lin.observer.plus; public class BaiDu implements Observer{ // 溫度,氣壓,溼度 private float temperatrue; private float pressure; private float humidity; // 更新天氣情況 public void update(float temperature, float pressure, float humidity) { this.temperatrue = temperature; this.pressure = pressure; this.humidity = humidity; display(); } public void display() { System.out.println("===BaiDu's temperature: " + temperatrue + "==="); System.out.println("===BaiDu's pressure: " + pressure + "==="); System.out.println("===BaiDu's humidity: " + humidity + "==="); } }
package com.lin.observer.plus; public class Client { public static void main(String[] args) { // 建立一個WeatherData WeatherData weatherData = new WeatherData(); // 建立觀察者 CurrentConditions currentConditions = new CurrentConditions(); BaiDu baiDu = new BaiDu(); // 註冊 weatherData.registerObserver(currentConditions); weatherData.registerObserver(baiDu); // 測試 System.out.println("通知各個註冊的觀察者:"); weatherData.setData(23, 12, -0.4f); } }
觀察者模式的好處
1) 觀察者模式設計後,會以集合的方式來管理使用者(Observer),包括註冊,移除和通知。
2) 這樣,我們增加觀察者(這裡可以理解成一個新的公告板),就不需要去修改核心類 WeatherData 不會修改程式碼, 遵守了 ocp 原則。
5 觀察者模式在 Jdk 應用的原始碼分析
1) Jdk 的 Observable 類就使用了觀察者模式
2) 程式碼分析+模式角色分析
3) 模式角色分析
- Observable 的作用和地位等價於 我們前面講過 Subject
- Observable 是類,不是介面,類中已經實現了核心的方法 ,即管理 Observer 的方法 add.. delete .. notify...
- Observer 的作用和地位等價於我們前面講過的 Observer, 有 update
- Observable 和 Observer 的使用方法和前面講過的一樣,只是 Observable 是類,通過繼承來實現觀察者模式
僅供參考,有錯誤還請指出!
有什麼想法,評論區留言,互相指教指教。