摘要:繼續我們的設計模式學習,有個好的觀察者可以讓你開發效率大大提高直接進入正題,我們用一個氣象站程序來模擬此模式。內置了觀察者模式的實現。
繼續我們的設計模式學習,有個好的“觀察者”可以讓你開發效率大大提高
直接進入正題,我們用一個氣象站程序來模擬此模式。
有一個氣象站程序,能對濕度,溫度,氣壓進行監測并顯示在“顯示”裝置上面
模擬圖如下,此系統中有三個部分
氣象站:獲取實際氣象數據的裝置
WeatherData對象:用來追蹤氣象站發出的數據,并實時更新到布告欄中
布告欄:顯示目前天氣狀況給用戶看的
換個比方來說說什么是觀察者模式~~~~
1:報社的業務就是出版報紙。
2:向某家報社訂閱報紙,只要他們有新報紙出版,就會給你送來,只要你是他們的客戶,你就會一直收到新報紙。
3:當你不想再看報紙的時候,取消訂閱,報社就不會給你送新報紙了。
4:只要報社一直存在,那么就一直會有人來訂閱或取消訂閱報紙的服務。
懂了嗎?出版社+訂閱者=觀察者模式,只不過用在“觀察者”中,出版社成為“主題”(Subject),訂閱者成為“觀察者”(Observer)
OK,讓我用視圖更好的說明
鴨子要加入了
目前只要主題那邊更新數據,在觀察者這邊就都能獲得數據了。
此時狗對象不想當觀察者了,它向“主題”提出了“離開”的意愿
狗對象離開了,當動物(主題)對象更新數據時,狗對象是不會更新的,它已經不是觀察者了,但同時它也可以回來重新“注冊”成觀察者。
自此觀察者模式的核心流程就是這樣了,代碼先不急著寫,先思考下。
觀察者模式定義:定義了對象之間一對多依賴,這么一來,當一個對象改變狀態時,它的所有依賴著都會收到自動更新。
這樣的設計使得主題和多個觀察者之間的依賴性降低了,Subject只管“交互”Observer,至于具體怎么實現內容或其他細節內容,Subject不需要知道,它只知道指向Observer就可以了。任何時候我們都可以增加新的觀察者,因為主題唯一依賴的東西是一個實現Observer接口的實現類,即使我們隨意增加刪除觀察者都不會影響主題,我們可以獨立地復用主題或觀察者,如果我們在其他地方需要使用主題或觀察者,可以輕易復用,因為二者并非緊耦合。
設計原則一:所做的一切都是為了對象之間能松耦合。(降低依賴度)
注:松耦合的設計之所以能讓我們建立有彈性的OO系統,能夠應對變化,是因為對象之間的相互依賴降到最低。
主題接口
package Interface; /** * 設計模式:觀察者模式 主題和觀察者之間有一對多關系 * * @author Joy * */ // 主題接口 public interface Subject { // 這兩個方法都需要一個觀察者作為變量(參數設為觀察者),該觀察者是用來注冊和刪除的 public void registerObserver(Observer o); public void removeObserver(Observer o); // 當主題狀態改變時調用這個方法,作用是通知觀察者 public void notifyObserver(); }
觀察者接口
package Interface; //觀察者接口 public interface Observer { //當氣象觀測數據改變時,主題會把新的狀態數據已參數形式傳遞給觀察者 public void update(float temp, float humidity, float pressure); }
顯示接口(顯示數據)
package Interface; public interface DisplayElement { public void display(); }
氣象站類(主題實現類)
package Implements; import java.util.ArrayList; import Interface.Observer; import Interface.Subject; //氣象站實現主題接口 //一個氣象站(主題)可以更新多個顯示(觀察者)面板值 public class WeatherData implements Subject { // 便于記錄觀察者 private ArrayList observers; private float temperature;//溫度 private float humidity;//濕度 private float pressure;//氣壓 public WeatherData() { observers = new ArrayList(); } // 當注冊觀察者時,我們只需要把它加入到ArrayList后面即可 @Override public void registerObserver(Observer o) { observers.add(o); } // 當觀察者想取消注冊時,從list中移除即可 @Override public void removeObserver(Observer o) { int i = observers.indexOf(o); if (i > 0) { observers.remove(i); } } @Override public void notifyObserver() { for (int i = 0; i < observers.size(); i++) { //建立觀察者對象 Interface.Observer observer = (Interface.Observer) observers.get(i); //將數據更新至觀察者對象內 observer.update(temperature, humidity, pressure); System.out.println("主題更新了數據,觀察者那同步更新"); } } // 當從氣象站得到更新觀測值時,我們通知觀察者 public void measurementsChanged() { notifyObserver(); } //設置溫度,濕度,壓力值 public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } }
下面是兩個觀察者實現類,氣溫濕度顯示裝置和天氣預報裝置
package Implements; import Interface.DisplayElement; import Interface.Observer; import Interface.Subject; //觀察者實現類 //氣溫,濕度顯示裝置 public class CurrentConditionDisplay implements Observer,DisplayElement { private float temperature; private float humidity; private Subject weatherData; //構造器需要weatherData對象,用于注冊 public CurrentConditionDisplay(Subject weatherData){ this.weatherData=weatherData; //注冊 weatherData.registerObserver(this); } @Override public void display() { System.out.println("溫度板"); System.out.println("溫度:"+temperature+" "+"濕度:"+humidity); } @Override public void update(float temperature, float humidity, float pressure) { this.temperature=temperature; this.humidity=humidity; //當update調用時,將溫度濕度數據保存起來然后調用display display(); } }
天氣預報類
package Implements; import Interface.DisplayElement; import Interface.Observer; /** * 天氣預報裝置 * * @author Joy * */ public class ForecastDisplay implements Observer, DisplayElement { private float currentPressure = 29.92f; // 當前壓力值(賦個初始值) private float lastPressure;// 上一次壓力值 private WeatherData weatherData; public ForecastDisplay(WeatherData weatherData) { this.weatherData = weatherData; // 注冊成觀察者 weatherData.registerObserver(this); } @Override public void update(float temp, float humidity, float pressure) { lastPressure = currentPressure; //pressure傳過來的壓力值 currentPressure = pressure; display(); } @Override public void display() { System.out.print("天氣預報: "); if (currentPressure > lastPressure) { System.out.println("天氣晴朗"); } else if (currentPressure == lastPressure) { System.out.println("這次天氣狀況與上一次相同"); } else if (currentPressure < lastPressure) { System.out.println("注意降溫,陰云多雨天氣"); } } }
測試類
package TestMain; import Implements.CurrentConditionDisplay; import Implements.ForecastDisplay; import Implements.WeatherData; public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionDisplay ccd = new CurrentConditionDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); //第一次天氣情況 weatherData.setMeasurements(80f, 65f, 30.4f); System.out.println(); //第二次天氣情況 weatherData.setMeasurements(82f, 70f, 29.2f); System.out.println(); //第三次天氣情況 weatherData.setMeasurements(78f, 90f, 29.2f); } }
運行效果
要點:
1:觀察者模式定義了對象之間一對多的關系。
2:主題用一個共同接口來更新觀察者。(update方法和Subject接口)
3:觀察者和可觀察者(主題)之間用松耦合的方式結合,可觀察者(主題)不知道觀察者的細節,只知道觀察者實現了觀察者接口。
4:Java內置了觀察者模式的實現。
自此完成了觀察者模式的實例,Java在JDK當中內置主題和觀察者的用法,這里為了更好理解,所以我寫的是自定義的形式,
這個模式理解起來并不難,但卻是個非常有用的模式,你現在就可以試著用觀察者和策略模式改改以前寫的舊代碼,我的感受就是隨著學習深入,就覺得以前寫的代碼很多都是有錯誤的。。。。。
感謝你看到這里,觀察者模式部分結束,本人文筆隨便,若有不足或錯誤之處望給予指點,90度彎腰~很快我會發布下一個設計模式內容,生命不息,編程不止!
參考書籍:《Head First 設計模式》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67612.html
摘要:設計模式的定義在面向對象軟件設計過程中針對特定問題的簡潔而優雅的解決方案。從前由于使用的局限性,和做的應用相對簡單,不被重視,就更談不上設計模式的問題。 ‘從大處著眼,從小處著手’,以前對這句話一知半解,自從踏出校門走入社會,開始工作以來,有了越來越深的理解,偶有發現這句話用在程序開發中也有用,所以,近段時間開始嘗試著分析jQuery源碼,分析angularjs源碼,學習設計模式。 設...
摘要:若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。裝飾者模式意味著一群裝飾者類,這些類用來包裝具體組件。裝飾者類反映出被裝飾組件類型。裝飾者會導致設計中出現許多小對象,如果過度使用,會讓程序變得很復雜。 嘿嘿嘿,你是不是很喜歡用繼承呢?感覺沒什么事情是一個爸爸類搞不定的,有的話就兩個,快來跟我看看這個模式吧,它能讓你斷奶,給愛用繼承的人一個全新的設計眼界。 直奔主題,你是否有聽說...
摘要:我們今天也來做一個萬能遙控器設計模式適配器模式將一個類的接口轉換成客戶希望的另外一個接口。今天要介紹的仍然是創建型設計模式的一種建造者模式。設計模式的理論知識固然重要,但 計算機程序的思維邏輯 (54) - 剖析 Collections - 設計模式 上節我們提到,類 Collections 中大概有兩類功能,第一類是對容器接口對象進行操作,第二類是返回一個容器接口對象,上節我們介紹了...
閱讀 3318·2021-11-23 09:51
閱讀 2435·2021-11-09 09:46
閱讀 1476·2019-08-30 15:54
閱讀 3121·2019-08-30 14:22
閱讀 2909·2019-08-29 12:40
閱讀 1629·2019-08-26 10:33
閱讀 1774·2019-08-23 17:09
閱讀 1553·2019-08-23 16:11