日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java 设计模式之观察者模式

發(fā)布時(shí)間:2024/9/30 java 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 设计模式之观察者模式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、了解觀察者模式

1.1 什么是觀察者模式

觀察者模式定義了對(duì)象之間的一對(duì)多依賴,這樣一來,當(dāng)一個(gè)對(duì)象狀態(tài)改變時(shí),它的所有依賴者都會(huì)收到通知并自動(dòng)更新。

典型的問題比如報(bào)社,只要你是他們的訂戶,他們每次有新報(bào)紙出版時(shí),就會(huì)向你這送來,當(dāng)你不想要看報(bào)紙時(shí),取消訂閱,他們就不會(huì)再給你送報(bào)紙。

1.2 觀察者模式組成結(jié)構(gòu)

  • 抽象主題 (Subject):抽象主題角色把所有觀察者對(duì)象保存在一個(gè)集合里,每個(gè)主題都可以有任意數(shù)量的觀察者,抽象主題提供一個(gè)接口,可以增加和刪除觀察者對(duì)象。
  • 具體主題 (ConcreteSubject):該角色將有關(guān)狀態(tài)存入具體觀察者對(duì)象,在具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),給所有注冊(cè)過的觀察者發(fā)送通知。
  • 抽象觀察者 (Observer):是觀察者的抽象類,它定義了一個(gè)更新接口,使得在得到主題更改通知時(shí)更新自己。
  • 具體觀察者 (ConcrereObserver):實(shí)現(xiàn)抽象觀察者定義的更新接口,以便在得到主題更改通知時(shí)更新自身的狀態(tài)。

1.3 觀察者模式 UML 圖解

二、觀察者模式具體應(yīng)用

2.1 問題描述

氣象觀測(cè)站系統(tǒng):該系統(tǒng)中包含三部分,分別是氣象站 (獲取實(shí)際氣象數(shù)據(jù)的物理裝置)、WeatherData 對(duì)象 (追蹤氣象站的數(shù)據(jù),并更新布告板) 和布告板 (顯示天氣狀況給用戶看,布告板共有兩個(gè),分別顯示當(dāng)前的溫度以及對(duì)天氣進(jìn)行預(yù)告)。

2.2 問題分析

我們想要使用觀察者模式去解決這個(gè)問題,首先要分析出什么是主題,什么是觀察者,問題的關(guān)鍵是找出一對(duì)多依賴關(guān)系。這里 WeatherData 類正如所說的“一”,而“多”是用于顯示天氣情況的布告板。

WeatherData 是有狀態(tài)的對(duì)象,它包括了溫度、濕度和氣壓,而這些值都會(huì)變化,當(dāng)這些值改變時(shí),必須通知布告板,好讓它們顯示最新的數(shù)據(jù)。所以把 WeatherData 類作為主題,布告板作為觀察者。

2.3 問題分析設(shè)計(jì)圖

2.4 代碼實(shí)現(xiàn)

PS:代碼模塊較多,建議將這些代碼拷下來運(yùn)行一遍。

抽象主題接口 Subject

package com.jas.observer;public interface Subject {/*** 注冊(cè)觀察者* * @param observer 觀察者對(duì)象*/void registObserver(Observer observer);/*** 移除觀察者** @param observer 觀察者對(duì)象*/void removeObserver(Observer observer);/*** 當(dāng)主題狀態(tài)改變時(shí),這個(gè)方法會(huì)被調(diào)用,通知所有的觀察者*/void notifyObservers(); }

抽象觀察者接口 Observer

package com.jas.observer;public interface Observer {/*** 當(dāng)氣象觀測(cè)值改變時(shí),主題會(huì)把這些狀態(tài)值作為參數(shù),傳送給觀察者* * @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 List<Observer> list = new ArrayList(); //使用集合保存所有的觀察者對(duì)象@Overridepublic void registObserver(Observer observer) {list.add(observer);}@Overridepublic void removeObserver(Observer observer) {int i = list.indexOf(observer);if(i >= 0 && i < list.size()){list.remove(i);}}@Overridepublic void notifyObservers() {for (int i = 0; i < list.size(); i++) { //遍歷集合中所有觀察者對(duì)象Observer observer = list.get(i);observer.update(temperature,humidity,pressure); //調(diào)用觀察者的 update() 方法}}/*** 當(dāng)氣象站的數(shù)據(jù)得到更新后,通知觀察者,調(diào)用 notifyObservers() 方法*/public void measurementsChanged(){notifyObservers();}/*** 當(dāng)氣象站數(shù)據(jù)改變后,設(shè)置新的數(shù)據(jù)值,并調(diào)用 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();} }

具體觀察者對(duì)象,當(dāng)前天氣信息類 CurrentConditionsDisplay

package com.jas.observer;public class CurrentConditionsDisplay implements Observer, DisplayElement {private float temperature;private float humidity;private float pressure;private Subject weatherData;/*** 通過構(gòu)造函數(shù)將當(dāng)前觀察者注冊(cè)給具體主題對(duì)象* * @param weatherData 主題對(duì)象*/public CurrentConditionsDisplay(Subject weatherData){this.weatherData = weatherData;weatherData.registObserver(this);}/*** 布告板信息展示*/@Overridepublic void display() {System.out.println("Current conditions list : " + "溫度 = " + temperature + ", 濕度 = " + humidity + ", 氣壓 = " + pressure);}/*** 更新信息* * @param temp 溫度* @param humidity 濕度* @param pressure 壓力*/@Overridepublic void update(float temp, float humidity, float pressure) {this.temperature = temp;this.humidity = humidity;this.pressure = pressure;display();} }

具體觀察者對(duì)象,預(yù)測(cè)天氣信息類 ForecastDisplay(簡(jiǎn)單將數(shù)據(jù)減一)

package com.jas.observer;public class ForecastDisplay implements Observer, DisplayElement {private float temperature;private float humidity;private float pressure;private Subject weatherData;/*** 通過構(gòu)造函數(shù)將當(dāng)前觀察者注冊(cè)給主題對(duì)象** @param weatherData 主題對(duì)象*/public ForecastDisplay(WeatherData weatherData){this.weatherData = weatherData;weatherData.registObserver(this);}@Overridepublic void display() {System.out.println("Forecast conditions list : " + "溫度 = " +(temperature - 1.0) + ", 濕度 = " + (humidity - 1.0) + ", 氣壓 = " + (pressure - 1.0));}@Overridepublic 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);//當(dāng)具體主題對(duì)象數(shù)據(jù)發(fā)生變化,所有依賴者 (觀察者) 都會(huì)實(shí)現(xiàn)自動(dòng)數(shù)據(jù)更新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 自定義觀察者模式總結(jié)

觀察者模式可以輕松實(shí)現(xiàn)松耦合,因?yàn)橹黝}并不需要知道觀察者的具體類是誰,做了些什么,并且我們可以在任何時(shí)候新增觀察者。由于一個(gè)主題可能對(duì)應(yīng)多個(gè)觀察者,所以當(dāng)某一個(gè)觀察者出現(xiàn)問題時(shí),可能導(dǎo)致其他的觀察者也不能正常工作。因此在一定程度上,存在著效率問題。

三、Java 內(nèi)置觀察者模式

3.1 了解 Java 內(nèi)置觀察者模式

java.util 包內(nèi) 包含最基本的Observable 類與 Observer 接口,這和上面的 Subject 接口與 Observer 接口很類似。Observable 類與 Observer 接口使用起來更方便,因?yàn)樵S多的功能已經(jīng)提供了。

3.2 Java 內(nèi)置觀察者模式如何運(yùn)作

(1)如何把對(duì)象定義為觀察者?

實(shí)現(xiàn)觀察者 (Observer) 接口,調(diào)用任何 Observable 對(duì)象的 addObserve() 方法。當(dāng)不想要當(dāng)觀察者時(shí),調(diào)用 deleteObserve() 方法。

(2)可觀察者如何發(fā)送通知?

  • 先調(diào)用 setChanged() 方法,標(biāo)記狀態(tài)已經(jīng)被改變的事實(shí)。
  • 調(diào)用 notifyObservers() 或 notifyObservers(Object arg) 方法。
  • (3)觀察者如何接收通知?

    同以前一樣,觀察者實(shí)現(xiàn)了 update(Observable o, Object arg) 方法,只是方法簽名不太一樣。

    3.3 重寫氣象觀測(cè)站系統(tǒng)

    主題類 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(){//在通知所有觀察者之前,先調(diào)用 setChanged() 方法,用來表示狀態(tài)已經(jīng)改變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;} }

    具體觀察者對(duì)象,當(dāng)前天氣信息類 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;/*** 通過構(gòu)造函數(shù),將當(dāng)前對(duì)象記錄為觀察者* * @param observable 主題對(duì)象*/public CurrentConditionsDisplay(Observable observable){this.observable = observable;observable.addObserver(this);}@Overridepublic void display() {System.out.println("Current conditions list : " + "溫度 = " +temperature + ", 濕度 = " + humidity + ", 氣壓 = " + pressure);}@Overridepublic 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 內(nèi)置觀察者模式總結(jié)

    Java 內(nèi)置的觀察者模式允許觀察者有選擇的獲取數(shù)據(jù),而不是主題對(duì)象強(qiáng)制將更新數(shù)據(jù)全部推送個(gè)每個(gè)觀察者。

    Observable 是一個(gè)類,并不是一個(gè)接口,這意味著你繼承它的同時(shí),不能再繼承其他的類。在 Observable 類中 setChanged() 方法被保護(hù)了起來 (protected),除非你繼承該類,否則你無法創(chuàng)建 Observable 實(shí)例組合到你自己的對(duì)象中來。所以它違反了一個(gè)原則:“多用組合,少用繼承”。

    還有一點(diǎn)需要要注意的是:內(nèi)置的觀察者模式,觀察者被通知的順序并不是唯一的 (上面只定義了一個(gè)觀察者),有時(shí)候并不能達(dá)到我們一開始的目的,你可以定義多個(gè)觀察者驗(yàn)證一下。

    根據(jù)具體的需求,如果 Java 內(nèi)置的觀察者模式 API 不能滿設(shè)計(jì),那么我們可以像剛開始那樣自己實(shí)現(xiàn)一套觀察者模式。

    PS:點(diǎn)擊了解更多設(shè)計(jì)模式 http://blog.csdn.net/codejas/article/details/79236013

    參考文獻(xiàn)

    《Head First 設(shè)計(jì)模式》

    總結(jié)

    以上是生活随笔為你收集整理的Java 设计模式之观察者模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。