设计模式(二)————观察者模式
引言
觀察者模式可以說(shuō)是JDK中使用最多的模式之一,這個(gè)模式可以讓你的對(duì)象隨時(shí)隨地的了解想要知道的情況,你還可以讓某個(gè)對(duì)象在運(yùn)行時(shí)決定是否要繼續(xù)通知;觀察者模式的定義為:
定義對(duì)象間一種一對(duì)多的依賴(lài)關(guān)系,使得當(dāng)每一個(gè)對(duì)象改變狀態(tài),則所有依賴(lài)于它的對(duì)象都會(huì)得到通知并自動(dòng)更新
從定義就可以看出,觀察者模式主要就是兩部分:主題(Subject)和觀察者(Observer)
為了更清楚的了解觀察者模式,下面將會(huì)用案例說(shuō)明觀察者模式;
天氣預(yù)報(bào)項(xiàng)目
今天一個(gè)新的項(xiàng)目交到了你的手上,這個(gè)項(xiàng)目是一個(gè)天氣預(yù)報(bào)公司的,他們想要
- 將每天測(cè)量到的溫度,濕度,氣壓等等以公告的形式發(fā)布出去
- 設(shè)計(jì)開(kāi)放型 API,便于其他第三方也能接入氣象站獲取數(shù)據(jù)
- 而且天氣預(yù)報(bào)最基本的要求是準(zhǔn)時(shí),不能開(kāi)始下雨了才把下雨的預(yù)報(bào)發(fā)出來(lái),所以很重要的一點(diǎn)是:每當(dāng)天氣預(yù)報(bào)更新的時(shí)候,要實(shí)時(shí)通知給第三方;
通過(guò)需求分析可以提煉出關(guān)鍵一點(diǎn):公布天氣信息的“布告板”可以有多個(gè),這些布告板全部從天氣預(yù)報(bào)公司獲取天氣信息;
大致是下圖的意思:
再加上實(shí)時(shí)更新的需求,就是對(duì)標(biāo)觀察者模式;
上面圖可以等同于下面這個(gè):
所以只需要確定好觀察者模式的兩個(gè)主要組成:主題(Subject)和觀察者(Observer)就好了;
很明顯,主題對(duì)象就是天氣預(yù)報(bào)公司,觀察者就是一系列第三方網(wǎng)站(的布告板);
接下來(lái)就是如何用方法將觀察者和主題聯(lián)系起來(lái)呢?
對(duì)于觀察者來(lái)說(shuō),需要的方法就是一個(gè):
- 接受主題的輸入(update)
對(duì)于主題來(lái)說(shuō),需要以下功能:
- registerObserver() 注冊(cè)
- removeObserver() 移除
- notifyObservers() 通知注冊(cè)的用戶(hù)
那么就可以簡(jiǎn)單嘗試畫(huà)出UML類(lèi)圖了:
大致就是這樣,Subject是主題的接口,Observer是觀察者的接口,
可能你會(huì)覺(jué)得上面明明就說(shuō)的那么簡(jiǎn)單,怎么這一下子多了好幾個(gè)東西
其實(shí)這樣子的代碼耦合度更低,而且思路非常簡(jiǎn)單,下面就來(lái)通過(guò)代碼實(shí)現(xiàn)一下就明白了;
主題:
觀察者:
還可以繼續(xù)增加布告板,這里就列舉這兩個(gè)了;
測(cè)試執(zhí)行代碼:
public class WeatherStation {public static void main(String[] args) {WeatherData weatherData = new WeatherData();Observer current = new CurrentConditionsDisplay(); // 自己網(wǎng)站的觀察者Observer baidu = new BaiDuDisplay(); // 百度觀察者weatherData.registerObserver(current); // 注冊(cè)觀察者weatherData.registerObserver(baidu); // 注冊(cè)觀察者weatherData.setMeasurements(11, 22, 33);} }運(yùn)行結(jié)果:
當(dāng)前溫度:11.0當(dāng)前濕度:22.0當(dāng)前壓力:33.0 百度溫度:11.0百度濕度:22.0百度壓力:33.0其實(shí)一看代碼,還是兩大部分,所以對(duì)于觀察者模式,主要思考的是主題和觀察者的關(guān)系就可以了;
使用了觀察者模式后,代碼有以下好處:
- 觀察者模式設(shè)計(jì)后,會(huì)以集合的方式來(lái)管理用戶(hù)(Observer),包括注冊(cè),移除和通知
- 增加觀察者(即成一個(gè)新的公告板),就不需要去修改核心類(lèi) WeatherData 的代碼,遵守 ocp (開(kāi)閉)原則
Java內(nèi)置觀察者模式
JDK中提供了 java.util.Observable 實(shí)現(xiàn)類(lèi)和 java.util.Observer 接口,這是Java內(nèi)置的觀察者模式,可以直接來(lái)用,先簡(jiǎn)單對(duì)比介紹一下:
- Observable 的作用和地位等價(jià)于前面的Subject
- Observable 是類(lèi),不是接口,類(lèi)中已經(jīng)實(shí)現(xiàn)了核心的方法 ,即管理 Observer 的方法 add… delete … notify…
- Observer 接口的作用等價(jià)于前面的 Observer接口, 都有update
- Observable類(lèi) 和 Observer接口 的使用方法和前面講過(guò)的一樣,只是 Observable 是類(lèi),通過(guò)繼承來(lái)實(shí)現(xiàn)觀察者模式
下面我將用內(nèi)置觀察者模式支持來(lái)重寫(xiě)一下上面的代碼實(shí)現(xiàn)相同的功能;
主題:
觀察者:
測(cè)試執(zhí)行代碼:
public class WeatherStation {public static void main(String[] args) {WeatherData weatherData = new WeatherData(); // 主題CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(); // 觀察者BaiDuDisplay baiDuDisplay = new BaiDuDisplay(); // 百度觀察者weatherData.addObserver(currentConditionsDisplay); // 增添觀察者weatherData.addObserver(baiDuDisplay);// 增添觀察者weatherData.setMeasurements(11, 22, 33);} }運(yùn)行結(jié)果:
百度溫度為:11.0 百度濕度為:22.0 百度壓力為:33.0 當(dāng)前溫度為:11.0 當(dāng)前濕度為:22.0 當(dāng)前壓力為:33.0是不是有很多相同的地方,歸根結(jié)底都是使用的觀察者模式,所以只要知道觀察者模式由什么組成,什么時(shí)候用,那么你就真正了解了觀察者模式;
但是設(shè)計(jì)模式可不是隨便看看這倆代碼就能會(huì)用的,這也是設(shè)計(jì)模式不好學(xué)的一點(diǎn),還是需要大量的代碼練習(xí)去體會(huì),最后就能靈活運(yùn)用;
注:在JDK中JavaBeans和Swing都實(shí)現(xiàn)了觀察者模式,感興趣可以嘗試一下;
總結(jié)
總結(jié)一下觀察者模式:
- 觀察者模式定義了對(duì)象之間一對(duì)多的關(guān)系
- 主題通過(guò)一個(gè)共同的接口來(lái)更新觀察者
- 觀察者和主題之間用松耦合的方式結(jié)合,主題不知道觀察者的細(xì)節(jié),只知道觀察者實(shí)現(xiàn)了觀察者接口
- 當(dāng)有多個(gè)觀察者時(shí),不能依賴(lài)特定的通知次序
最后在這里展示一下觀察者模式的UML類(lèi)圖:
在這篇文章中的例子的代碼只是為了展示觀察者模式,但是并不是最優(yōu)的代碼,一個(gè)好的代碼可能要用到多種設(shè)計(jì)模式,這也是設(shè)計(jì)模式的一個(gè)難點(diǎn);
設(shè)計(jì)模式的學(xué)習(xí)沒(méi)有什么技巧,只能在敲代碼的過(guò)程中不斷去體會(huì),可能某一天你就會(huì)不自覺(jué)的使用設(shè)計(jì)模式,還是要多敲代碼多踩坑多思考,希望我們一起努力!!
歡迎大家的點(diǎn)評(píng)!
總結(jié)
以上是生活随笔為你收集整理的设计模式(二)————观察者模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 数据结构解析——小白也能看懂的单链表
- 下一篇: [Java基础]Map集合的遍历