开发之路(设计模式二:观察者模式)
直接進入正題,我們用一個氣象站程序來模擬此模式。
有一個氣象站程序,能對濕度,溫度,氣壓進行監測并顯示在“顯示”裝置上面
模擬圖如下,此系統中有三個部分
氣象站:獲取實際氣象數據的裝置
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后面即可@Overridepublic void registerObserver(Observer o) {observers.add(o);}// 當觀察者想取消注冊時,從list中移除即可@Overridepublic void removeObserver(Observer o) {int i = observers.indexOf(o);if (i > 0) {observers.remove(i);}}@Overridepublic 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);}@Overridepublic void display() {System.out.println("溫度板");System.out.println("溫度:"+temperature+"\t"+"濕度:"+humidity); }@Overridepublic void update(float temperature, float humidity, float pressure) {this.temperature=temperature;this.humidity=humidity;//當update調用時,將溫度濕度數據保存起來然后調用displaydisplay(); } }天氣預報類
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);}@Overridepublic void update(float temp, float humidity, float pressure) {lastPressure = currentPressure;//pressure傳過來的壓力值currentPressure = pressure;display();}@Overridepublic 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 設計模式》總結
以上是生活随笔為你收集整理的开发之路(设计模式二:观察者模式)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 创造与魔法牛蛙可以做什么
- 下一篇: 百会CRM教你在大数据平台中做精准营销