觀察者模式還是非常常用的,常見于基于zookeeper進(jìn)行分布式系統(tǒng)之間的協(xié)調(diào)工作,比如分布式鎖的注冊以及監(jiān)聽是否釋放。還有就是兩個(gè)系統(tǒng)之間如果做了異步的處理,那么如果A系統(tǒng)發(fā)送異步請求給了B系統(tǒng),但是要得到B系統(tǒng)的一個(gè)狀態(tài)改變的消息,可以采用觀察者模式。
創(chuàng)新互聯(lián)建站主營長安網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,app軟件開發(fā),長安h5小程序定制開發(fā)搭建,長安網(wǎng)站營銷推廣歡迎長安等地區(qū)企業(yè)咨詢
使用場景
在Zookeeper中的監(jiān)聽回調(diào)機(jī)制,以及分布式鎖,都是使用了觀察者模式。
基于zookeeper去做分布式鎖
(1)系統(tǒng)A嘗試獲取zookeeper上的一個(gè)鎖,獲取到了
(2)系統(tǒng)B嘗試獲取zookeeper上的一個(gè)鎖,被系統(tǒng)A給鎖了,沒有獲取到鎖,此時(shí)系統(tǒng)B在zookeeper上可以注冊一個(gè)監(jiān)聽器(觀察者)
(3)系統(tǒng)A一旦將鎖給釋放了,zookeeper感受到鎖被釋放了,就會立即通知系統(tǒng)B注冊的那個(gè)監(jiān)聽器
(4)系統(tǒng)B就立即被通知到了,系統(tǒng)A釋放了鎖,系統(tǒng)B可以重新嘗試在zookeeper上加鎖
電商系統(tǒng)里,也有這種場景,如果兩個(gè)系統(tǒng)之間走了異步請求,那么可以基于上面那種觀察者模式現(xiàn)在一個(gè)進(jìn)程內(nèi)實(shí)現(xiàn)監(jiān)聽,以后拆分微服務(wù)分布式架構(gòu)了,可以改成基于zookeeper來做分布式協(xié)調(diào)。
系統(tǒng)A發(fā)送了一條消息到內(nèi)存隊(duì)列,系統(tǒng)B獲取了消息開始執(zhí)行操作
但是系統(tǒng)A需要知道系統(tǒng)B的一個(gè)執(zhí)行的結(jié)果如何,
此時(shí)系統(tǒng)A需要注冊一個(gè)觀察者到系統(tǒng)B上去,系統(tǒng)B執(zhí)行完了之后,將執(zhí)行的結(jié)果,反過來通知給系統(tǒng)
我們就可以基于觀察者模式去做。
官方解釋:
觀察者模式(有時(shí)又被稱為發(fā)布-訂閱Subscribe模式、模型-視圖View模式、源-收聽者Listener模式或從屬者模式)是軟件設(shè)計(jì)模式的一種。在此種模式中,一個(gè)目標(biāo)物件管理所有相依于它的觀察者物件,并且在它本身的狀態(tài)改變時(shí)主動發(fā)出通知。這通常透過呼叫各觀察者所提供的方法來實(shí)現(xiàn)。此種模式通常被用來實(shí)作事件處理系統(tǒng)。
個(gè)人理解:
觀察者模式是一種思想,不需要人為的去關(guān)注觀察者和被觀察者之間是怎樣聯(lián)系的,實(shí)現(xiàn)了解耦,只需要對象去注冊被觀察者(Observerable)與觀察者(Observer),然后被觀察者去添加一個(gè)或者多個(gè)觀察者,當(dāng)被觀察者發(fā)生變動就會立即通知所有的觀察者,下面讓我們來看看是怎樣實(shí)現(xiàn)這個(gè)功能的。
被觀察者首先通過addObserver(Observer o)來添加一個(gè)觀察者,底層代碼中會把這個(gè)對象o放進(jìn)一個(gè)vector集合中,當(dāng)然也可以添加多個(gè)觀察者,當(dāng)觀察者發(fā)生變動的時(shí)候就會觸發(fā)
setChanged();
notifyObservers();
這兩個(gè)方法,然后底層代碼中就回去遍歷裝有觀察者的那個(gè)vector,然后
for (int i = arrLocal.length-1; i=0; i--)
((Observer)arrLocal[i]).update(this, arg);
調(diào)用update方法通知每一個(gè)觀察者,這樣觀察者對象中就可以拿到被觀察者的相關(guān)對象和信息
當(dāng)我們想訂一份報(bào)紙,我們先去郵局找到報(bào)紙的編號后填寫訂閱單并繳費(fèi)。當(dāng)報(bào)社有新報(bào)紙發(fā)出時(shí),郵局會將我們訂閱的報(bào)紙發(fā)給我們。
為了簡單我們?nèi)サ羿]局環(huán)節(jié)簡化成:報(bào)社有新報(bào)紙后馬上通知用戶,這就是觀察者。
定義對象間的一對多關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生變化時(shí),所依賴于它的對象都得到通知并主動更新。 在觀察者模式中,多個(gè)訂閱者成為觀察者(Observer),被觀察的對象成為目標(biāo)(Subject)。觀察者的UML模型如下:
先定義Subject并寫一個(gè)ConcreteSubject繼承Subject:
再定義一個(gè)接口Observer,并寫一個(gè)ConcreteObserver實(shí)現(xiàn)Observer接口:
最后看看主函數(shù)方法:
打印出來的結(jié)果:
在實(shí)現(xiàn)觀察者模式的時(shí)候,一定要注意觸發(fā)通知的時(shí)機(jī)。一般情況下是在完成了狀態(tài)改變之后觸發(fā),因?yàn)橥ㄖ獣鬟f數(shù)據(jù),比如在 setSubjectState 時(shí)先通知觀測者就會發(fā)生 錯(cuò)誤 。
在觀察者模式的實(shí)現(xiàn)上,有推模式和拉模式兩種方式:
當(dāng)前上面的實(shí)現(xiàn)使用的就是拉模型。通過 (ConcreteSubject)subject 得到具體對象,獲得信息。
當(dāng)然Java本身就有觀察者模式的部分實(shí)現(xiàn),分別是 java.util.Observable java.util.Observable 。
下面看一個(gè)使用Java自帶觀察者模式的例子:
新的目標(biāo)直接繼承Java中定義的Observerable:
新的觀察者也直接實(shí)現(xiàn)Observer接口:
主函數(shù)和前面的相似:
打印出結(jié)果:
使用Java自帶的觀察者模式需要注意以下幾個(gè)問題:
觀察者(Observer)模式又名發(fā)布-訂閱(Publish/Subscribe)模式。GOF給觀察者模式如下定義:定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對象都得到通知并被自動更新。
在這里先講一下面向?qū)ο笤O(shè)計(jì)的一個(gè)重要原則——單一職責(zé)原則。因此系統(tǒng)的每個(gè)對象應(yīng)該將重點(diǎn)放在問題域中的離散抽象上。因此理想的情況下,一個(gè)對象只做一件事情。這樣在開發(fā)中也就帶來了諸多的好處:提供了重用性和維護(hù)性,也是進(jìn)行重構(gòu)的良好的基礎(chǔ)。
因此幾乎所有的設(shè)計(jì)模式都是基于這個(gè)基本的設(shè)計(jì)原則來的。觀察者模式的起源我覺得應(yīng)該是在GUI和業(yè)務(wù)數(shù)據(jù)的處理上,因?yàn)楝F(xiàn)在絕大多數(shù)講解觀察者模式的例子都是這一題材。但是觀察者模式的應(yīng)用決不僅限于此一方面。
下面我們就來看看觀察者模式的組成部分。
1)抽象目標(biāo)角色(Subject):目標(biāo)角色知道它的觀察者,可以有任意多個(gè)觀察者觀察同一個(gè)目標(biāo)。并且提供注冊和刪除觀察者對象的接口。目標(biāo)角色往往由抽象類或者接口來實(shí)現(xiàn)。
2)抽象觀察者角色(Observer):為那些在目標(biāo)發(fā)生改變時(shí)需要獲得通知的對象定義一個(gè)更新接口。抽象觀察者角色主要由抽象類或者接口來實(shí)現(xiàn)。
3)具體目標(biāo)角色(ConcreteSubject):將有關(guān)狀態(tài)存入各個(gè)ConcreteObserver對象。當(dāng)它的狀態(tài)發(fā)生改變時(shí),向它的各個(gè)觀察者發(fā)出通知。
4)具體觀察者角色(ConcreteObserver):存儲有關(guān)狀態(tài),這些狀態(tài)應(yīng)與目標(biāo)的狀態(tài)保持一致。實(shí)現(xiàn)Observer的更新接口以使自身狀態(tài)與目標(biāo)的狀態(tài)保持一致。在本角色內(nèi)也可以維護(hù)一個(gè)指向ConcreteSubject對象的引用。
定義 :對象間的一種一對多的依賴關(guān)系,使得當(dāng)每一個(gè)對象改變狀態(tài),則所有依賴于他的對象都會得到通知,并自動更新。
交互對象之間松耦合
1)觀察者定義了對象之間一對多的關(guān)系
2)被觀察者用一個(gè)共同的接口來更新觀察者
3)觀察者和被觀察者用松耦合方式結(jié)合,被觀察者不知道觀察者的細(xì)節(jié),只知道觀察者實(shí)現(xiàn)了觀察者接口
優(yōu)點(diǎn):
1)觀察者與被觀察者抽象耦合,容易擴(kuò)展;
2)建立了一套觸發(fā)機(jī)制。
缺點(diǎn):
1)循環(huán)依賴會導(dǎo)致系統(tǒng)崩潰;
2)觀察者太多會浪費(fèi)時(shí)間。
1)定義對象之間的一對多依賴關(guān)系而不使對象緊密耦合。
2)確保當(dāng)一個(gè)對象改變狀態(tài)時(shí),自動更新開放數(shù)量的從屬對象。
3)一個(gè)對象應(yīng)該可以通知開放式數(shù)量的其他對象。
觀察者模式 vs 發(fā)布-訂閱模式
觀察者模式(Observer)
如何使用 Java8 實(shí)現(xiàn)觀察者模式?(上)
如何使用 Java8 實(shí)現(xiàn)觀察者模式?(下)
spring 事件為bean 與 bean之間傳遞消息。一個(gè)bean處理完了希望其余一個(gè)接著處理.這時(shí)我們就需要其余的一個(gè)bean監(jiān)聽當(dāng)前bean所發(fā)送的事件.
spring事件使用步驟如下:
1.先自定義事件:你的事件需要繼承 ApplicationEvent
2.定義事件監(jiān)聽器: 需要實(shí)現(xiàn) ApplicationListener
3.使用容器對事件進(jìn)行發(fā)布
最后有一個(gè)思考 :ApplicationEvent事件執(zhí)行部分和起一個(gè)TaskExecutor去執(zhí)行 有啥區(qū)別嗎?反正都是異步。
可以這樣實(shí)現(xiàn);
還可以這樣實(shí)現(xiàn);
我的思考:ApplicationEvent是觀察者設(shè)計(jì)模式,這種設(shè)計(jì)模式使得主題和觀察者之間的耦合度降低,松耦合是面向?qū)ο笤O(shè)計(jì)中很重要的一個(gè)原則,最終也是使用@Async來實(shí)現(xiàn)異步。而TaskExecutor則是啟動一個(gè)線程池任務(wù)異步執(zhí)行任務(wù),兩者效果一樣,但原理不同。
通過我的思考,又帶來一個(gè)疑問:那觀察者模式是不是就是我們MQ中的發(fā)布訂閱模式呢?只不過觀察者模式是進(jìn)程內(nèi)的,而MQ是跨進(jìn)程的?就這唯一的區(qū)別嗎?
經(jīng)過一些資料的查閱:大多數(shù)地方觀察者模式 約等于 發(fā)布訂閱模式,但是觀察者模式是由具體目標(biāo)調(diào)度的,而發(fā)布/訂閱模式是統(tǒng)一由調(diào)度中心調(diào)的,所以觀察者模式的訂閱者與發(fā)布者之間是存在依賴的,而發(fā)布/訂閱模式則不會。
所以說觀察者模式是小米加步槍,發(fā)布訂閱模式是95式自動步槍,是它的進(jìn)化版!
網(wǎng)頁標(biāo)題:go語言實(shí)現(xiàn)觀察者模式 go 觀察者模式
網(wǎng)站網(wǎng)址:http://chinadenli.net/article12/dodsggc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供、品牌網(wǎng)站設(shè)計(jì)、關(guān)鍵詞優(yōu)化、網(wǎng)站設(shè)計(jì)公司、手機(jī)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)