摘要:三內置觀察者模式了解內置觀察者模式包內包含最基本的類與接口,這和上面的接口與接口很類似。根據具體的需求,如果內置的觀察者模式不能滿設計,那么我們可以像剛開始那樣自己實現一套觀察者模式。參考資料設計模式
一、了解觀察者模式
1.1 什么是觀察者模式
觀察者模式定義了對象之間的一對多依賴,這樣一來,當一個對象狀態改變時,它的所有依賴者都會收到通知并自動更新。
典型的問題比如報社,只要你是他們的訂戶,他們每次有新報紙出版時,就會向你這送來,當你不想要看報紙時,取消訂閱,他們就不會再給你送報紙。
1.2 觀察者模式組成結構
抽象主題 (Subject):抽象主題角色把所有觀察者對象保存在一個集合里,每個主題都可以有任意數量的觀察者,抽象主題提供一個接口,可以增加和刪除觀察者對象。
具體主題 (ConcreteSubject):該角色將有關狀態存入具體觀察者對象,在具體主題的內部狀態發生改變時,給所有注冊過的觀察者發送通知。
抽象觀察者 (Observer):是觀察者的抽象類,它定義了一個更新接口,使得在得到主題更改通知時更新自己。
具體觀察者 (ConcrereObserver):實現抽象觀察者定義的更新接口,以便在得到主題更改通知時更新自身的狀態。
1.3 觀察者模式 UML 圖解
二、觀察者模式具體應用2.1 問題描述
氣象觀測站系統:該系統中包含三部分,分別是氣象站 (獲取實際氣象數據的物理裝置)、WeatherData 對象 (追蹤氣象站的數據,并更新布告板) 和布告板 (顯示天氣狀況給用戶看,布告板共有兩個,分別顯示當前的溫度以及對天氣進行預告)。
2.2 問題分析
我們想要使用觀察者模式去解決這個問題,首先要分析出什么是主題,什么是觀察者,問題的關鍵是找出一對多依賴關系。這里 WeatherData 類正如所說的“一”,而“多”是用于顯示天氣情況的布告板。
WeatherData 是有狀態的對象,它包括了溫度、濕度和氣壓,而這些值都會變化,當這些值改變時,必須通知布告板,好讓它們顯示最新的數據。所以把 WeatherData 類作為主題,布告板作為觀察者。
2.3 問題分析設計圖
2.4 代碼實現
PS:代碼模塊較多,建議將這些代碼拷下來運行一遍。
抽象主題接口 Subject
package com.jas.observer; public interface Subject { /** * 注冊觀察者 * * @param observer 觀察者對象 */ void registObserver(Observer observer); /** * 移除觀察者 * * @param observer 觀察者對象 */ void removeObserver(Observer observer); /** * 當主題狀態改變時,這個方法會被調用,通知所有的觀察者 */ void notifyObservers(); }
抽象觀察者接口 Observer
package com.jas.observer; public interface Observer { /** * 當氣象觀測值改變時,主題會把這些狀態值作為參數,傳送給觀察者 * * @param temp 溫度 * @param humidity 濕度 * @param pressure 壓力 */ void update(float temp, float humidity, float pressure); }
布告信息接口 DisplayElement
package com.jas.observer; public interface DisplayElement { void display(); }
具體主題類 WeatherData
package com.jas.observer; import java.util.ArrayList; import java.util.List; public class WeatherData implements Subject { private float temperature; private float humidity; private float pressure; private Listlist = new ArrayList(); //使用集合保存所有的觀察者對象 @Override public void registObserver(Observer observer) { list.add(observer); } @Override public void removeObserver(Observer observer) { int i = list.indexOf(observer); if(i >= 0 && i < list.size()){ list.remove(i); } } @Override public void notifyObservers() { for (int i = 0; i < list.size(); i++) { //遍歷集合中所有觀察者對象 Observer observer = list.get(i); observer.update(temperature,humidity,pressure); //調用觀察者的 update() 方法 } } /** * 當氣象站的數據得到更新后,通知觀察者,調用 notifyObservers() 方法 */ public void measurementsChanged(){ notifyObservers(); } /** * 當氣象站數據改變后,設置新的數據值,并調用 measurementsChanged() 方法 * * @param temperature 溫度 * @param humidity 濕度 * @param pressure 氣壓 */ public void setMeasurements(float temperature, float humidity, float pressure){ this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } }
具體觀察者對象,當前天氣信息類 CurrentConditionsDisplay
package com.jas.observer; public class CurrentConditionsDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private float pressure; private Subject weatherData; /** * 通過構造函數將當前觀察者注冊給具體主題對象 * * @param weatherData 主題對象 */ public CurrentConditionsDisplay(Subject weatherData){ this.weatherData = weatherData; weatherData.registObserver(this); } /** * 布告板信息展示 */ @Override public void display() { System.out.println("Current conditions list : " + "溫度 = " + temperature + ", 濕度 = " + humidity + ", 氣壓 = " + pressure); } /** * 更新信息 * * @param temp 溫度 * @param humidity 濕度 * @param pressure 壓力 */ @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; this.pressure = pressure; display(); } }
具體觀察者對象,預測天氣信息類 ForecastDisplay(簡單將數據減一)
package com.jas.observer; public class ForecastDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private float pressure; private Subject weatherData; /** * 通過構造函數將當前觀察者注冊給主題對象 * * @param weatherData 主題對象 */ public ForecastDisplay(WeatherData weatherData){ this.weatherData = weatherData; weatherData.registObserver(this); } @Override public void display() { System.out.println("Forecast conditions list : " + "溫度 = " + (temperature - 1.0) + ", 濕度 = " + (humidity - 1.0) + ", 氣壓 = " + (pressure - 1.0)); } @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; this.pressure = pressure; display(); } }
氣象站類 WeatherStation
package com.jas.observer; public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); //當具體主題對象數據發生變化,所有依賴者 (觀察者) 都會實現自動數據更新 weatherData.setMeasurements(18,65,30); } } /** * 輸出 * Current conditions list : 溫度 = 18.0, 濕度 = 65.0, 氣壓 = 30.0 * Forecast conditions list : 溫度 = 17.0, 濕度 = 64.0, 氣壓 = 29.0 */
2.5 自定義觀察者模式總結
觀察者模式可以輕松實現松耦合,因為主題并不需要知道觀察者的具體類是誰,做了些什么,并且我們可以在任何時候新增觀察者。由于一個主題可能對應多個觀察者,所以當某一個觀察者出現問題時,可能導致其他的觀察者也不能正常工作。因此在一定程度上,存在著效率問題。
三、Java 內置觀察者模式3.1 了解 Java 內置觀察者模式
java.util 包內包含最基本的Observable 類與 Observer 接口,這和上面的 Subject 接口與 Observer 接口很類似。Observable 類與 Observer 接口使用起來更方便,因為許多的功能已經提供了。
3.2 Java 內置觀察者模式如何運作
(1)如何把對象定義為觀察者?
實現觀察者 (Observer) 接口,調用任何 Observable 對象的 addObserve() 方法。當不想要當觀察者時,調用 deleteObserve() 方法。
(2)可觀察者如何發送通知?
先調用 setChanged() 方法,標記狀態已經被改變的事實。
調用 notifyObservers() 或 notifyObservers(Object arg) 方法。
(3)觀察者如何接收通知?
同以前一樣,觀察者實現了 update(Observable o, Object arg) 方法,只是方法簽名不太一樣。
3.3 重寫氣象觀測站系統
主題類 WeatherData
package com.jas.jdk.observer; import java.util.Observable; public class WeatherData extends Observable { private float temperature; private float humidity; private float pressure; public void measurementsChanged(){ //在通知所有觀察者之前,先調用 setChanged() 方法,用來表示狀態已經改變 setChanged(); notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure){ this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } public float getTemperature(){ return temperature; } public float getHumidity(){ return humidity; } public float getPressure() { return pressure; } }
具體觀察者對象,當前天氣信息類 CurrentConditionsDisplay
package com.jas.jdk.observer; import java.util.Observable; import java.util.Observer; public class CurrentConditionsDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private float pressure; private Observable observable; /** * 通過構造函數,將當前對象記錄為觀察者 * * @param observable 主題對象 */ public CurrentConditionsDisplay(Observable observable){ this.observable = observable; observable.addObserver(this); } @Override public void display() { System.out.println("Current conditions list : " + "溫度 = " + temperature + ", 濕度 = " + humidity + ", 氣壓 = " + pressure); } @Override public void update(Observable o, Object arg) { if(o instanceof WeatherData){ WeatherData weatherData = (WeatherData) o; this.temperature = weatherData.getTemperature(); this.humidity = weatherData.getHumidity(); this.pressure = weatherData.getPressure(); display(); } } }
氣象站類 WeatherStation(同上)
package com.jas.jdk.observer; public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); //ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); weatherData.setMeasurements(80,65,30.4f); } } /** * 輸出 * Current conditions list : 溫度 = 80.0, 濕度 = 65.0, 氣壓 = 30.4 */
3.4 Java 內置觀察者模式總結
Java 內置的觀察者模式允許觀察者有選擇的獲取數據,而不是主題對象強制將更新數據全部推送個每個觀察者。
Observable 是一個類,并不是一個接口,這意味著你繼承它的同時,不能再繼承其他的類。在 Observable 類中 setChanged() 方法被保護了起來 (protected),除非你繼承該類,否則你無法創建 Observable 實例組合到你自己的對象中來。所以它違反了一個原則:“多用組合,少用繼承”。
還有一點需要要注意的是:內置的觀察者模式,觀察者被通知的順序并不是唯一的 (上面只定義了一個觀察者),有時候并不能達到我們一開始的目的,你可以定義多個觀察者驗證一下。
根據具體的需求,如果 Java 內置的觀察者模式 API 不能滿設計,那么我們可以像剛開始那樣自己實現一套觀察者模式。
參考資料《Head First 設計模式》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77238.html
摘要:觀察者模式的使用場景比如你微博關注了一個人,那么這個人發布的微博就會推送到你這。 Java設計模式之觀察者模式 一直想寫一篇學習觀察者模式的總結沒有契機,今天學習阻塞隊列的原理時候看到在實現生產者消費者的時候用到了通知模式,就是所謂的觀察者模式,正好順便整理一下。 1. 簡介 觀察者模式定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更...
摘要:觀察者模式也稱發布訂閱模式它的作用就是當一個對象的狀態發生改變時,所有依賴于它的對象都將得到通知,自動刷新對象狀態舉個生活比較常見常見的例子比如你去面試之后,面試官看你表現不錯,最后會跟你要聯系方式,以便之后可以聯系你。 觀察者模式也稱發布-訂閱模式,它的作用就是當一個對象的狀態發生改變時,所有依賴于它的對象都將得到通知,自動刷新對象狀態 舉個生活比較常見常見的例子,比如你去面試之后,...
摘要:關鍵概念理解觀察者設計模式中主要區分兩個概念觀察者指觀察者對象,也就是消息的訂閱者被觀察者指要觀察的目標對象,也就是消息的發布者。 原文首發于微信公眾號:jzman-blog,歡迎關注交流! 最近補一下設計模式相關的知識,關于觀察者設計模式主要從以下幾個方面來學習,具體如下: 什么是觀察者設計模式 關鍵概念理解 通知觀察者的方式 觀察者模式的實現 觀察者模式的優缺點 使用場景 下面...
本文從jdk內置的觀察者模式來介紹觀察者模式。業務場景:當老師進門的時候,班長帶頭叫老師好,然后全班同學一起交老師好因為太簡單,直接上代碼 班長繼承自Observable package Observer; import java.util.Observable; import java.util.Observer; public class Monitor extends Observabl...
摘要:觀察者模式,是一對多的關系,一個主題對應多個觀察者,當這個主題發生變化的時候,所有觀察著這個主題的觀察者都會接收到通知來獲悉主題的變化。這就是使用的觀察者模式,下面就讓我們用代碼實現觀察者模式。 觀察者模式,是一對多的關系,一個主題對應多個觀察者,當這個主題發生變化的時候,所有觀察著這個主題的觀察者都會接收到通知來獲悉主題的變化。 在現實中我們也會遇到許許多多應用觀察者模式的行為,比如...
閱讀 2603·2021-10-14 09:43
閱讀 3564·2021-10-13 09:39
閱讀 3295·2019-08-30 15:44
閱讀 3146·2019-08-29 16:37
閱讀 3711·2019-08-29 13:17
閱讀 2739·2019-08-26 13:57
閱讀 1831·2019-08-26 11:59
閱讀 1250·2019-08-26 11:46