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