观察者模式 Observer 发布订阅模式 源 监听 行为型 设计模式(二十三)
生活随笔
收集整理的這篇文章主要介紹了
观察者模式 Observer 发布订阅模式 源 监听 行为型 设计模式(二十三)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
觀察者模式 Observer
是一個(gè)interface,定義了一個(gè)update方法
void update(Observable o, Object arg);
接受兩個(gè)參數(shù),一個(gè)是被觀察對(duì)象,一個(gè)是參數(shù) 被觀察角色Observerable 等同于前文Subject 內(nèi)部使用Vector維護(hù)觀察者Observer 提供了對(duì)觀察者的管理相關(guān)方法,添加、刪除、計(jì)算個(gè)數(shù)、刪除、刪除所有等 Observerable內(nèi)部使用標(biāo)志位記錄是否已經(jīng)發(fā)生變化 ??? private boolean changed = false; 發(fā)生變動(dòng)后,設(shè)置為true,通知后設(shè)置為false
Observerable的實(shí)現(xiàn)原理很簡(jiǎn)單:
意圖
定義對(duì)象一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴他的對(duì)象都得到通知并自動(dòng)更新。 別名:依賴(Dependents),發(fā)布訂閱(Publish-Subscribe)源-監(jiān)聽(tīng)(Source-Listener) ? 《Hold On, We're Going Home》是加拿大說(shuō)唱歌手德雷克與制作組合Majid Jordan合作的節(jié)奏布魯斯歌曲 第一句“I got my eyes on you”就是“我一直關(guān)注你” I got my eyes on you, You're everything that I see I want your hot love and emotion, endlessly I can't get over you, You left your mark on me...... 電視劇中,也是經(jīng)常出現(xiàn)”觀察、監(jiān)視“,比如《黎明之前》 是劉江執(zhí)導(dǎo)2010年出品的諜戰(zhàn)劇,由吳秀波、林永健、陸劍民、海清等領(lǐng)銜主演。豆瓣評(píng)分高達(dá)9.2。 有一段周漢亭被盯梢的橋段,有負(fù)責(zé)門口監(jiān)視的,有負(fù)責(zé)電話匯報(bào)情況的,有負(fù)責(zé)指揮的....他的一舉一動(dòng)都在敵人的監(jiān)視之內(nèi),引發(fā)無(wú)數(shù)個(gè)探子連鎖行動(dòng)。 歌詞中因?yàn)橄矚g妹子所以持續(xù)關(guān)注,妹子是目標(biāo),歌手是觀察者。 電視劇中敵人為了破壞我黨工作,所以監(jiān)視,周漢亭是目標(biāo),眾多探子是觀察者。 通過(guò)對(duì)目標(biāo)的觀察,觀察者可以獲得事物的動(dòng)向情況,進(jìn)而做出進(jìn)一步的行動(dòng)。這就是觀察。 在程序中,也經(jīng)常會(huì)出現(xiàn)這種場(chǎng)景 一個(gè)系統(tǒng)中必然由多個(gè)相互協(xié)作的類組成,很常見(jiàn)的問(wèn)題就是維持狀態(tài)的一致性或者說(shuō)聯(lián)動(dòng)效果。 觀察者模式就是為了解決這種問(wèn)題,處理“協(xié)作者”之間的一致性與聯(lián)動(dòng)問(wèn)題。 比如,數(shù)據(jù)庫(kù)中對(duì)某個(gè)字段進(jìn)行了更新,可能需要同步修改其他字段 比如,執(zhí)行一個(gè)main方法,IDE的窗口的聯(lián)動(dòng)效果,如下圖所示,點(diǎn)擊run執(zhí)行后 底部狀態(tài)欄會(huì)顯示Build狀態(tài),很快完成后就開(kāi)始運(yùn)行,側(cè)邊欄顯示運(yùn)行狀態(tài),然后控制臺(tái)打印輸出信息 這是一系列的聯(lián)動(dòng)效果 比如,同一份數(shù)據(jù)有多種圖表展示,如果數(shù)據(jù)發(fā)生變化,每個(gè)圖表都需要發(fā)生變化結(jié)構(gòu)
假設(shè)目標(biāo)為Subject ,觀察者為Observer(一個(gè)或者多個(gè)) 最簡(jiǎn)單的實(shí)現(xiàn)方式,就是Subject直接調(diào)用Observer的方法。 當(dāng)事件發(fā)生后,直接調(diào)用Observer的相關(guān)方法。 偽代碼如下 Subject內(nèi)使用List維護(hù)觀察者 當(dāng)事件發(fā)生,也就是方法f()中,循環(huán)通知觀察者 省略了觀察者的維護(hù)工作,也就是添加和刪除 class Subject{ List<Observer> observerList = new ArrayList<>(); void f(){ //do sth... for(Observer o:observerList){ //調(diào)用相關(guān)方法 o.doSthElse(); } }?
依賴倒置原則中,要求應(yīng)該面向抽象進(jìn)行編程,而不是面向細(xì)節(jié)。 上面的結(jié)構(gòu)中,不管是目標(biāo)還是觀察者的擴(kuò)展都不方便,所以抽象提取。 這就是觀察者模式的基本結(jié)構(gòu)。 抽象觀察者角色Observer 為所有的具體的觀察者定義一個(gè)接口,得到主題的通知信息后,進(jìn)行同步響應(yīng)。 一般包含一個(gè)方法叫做update()用以同步響應(yīng) 抽象主題角色Subject 主題角色把所有觀察者對(duì)象保存在集合中,提供管理工作,添加和刪除 并且,提供通知工作,也就是調(diào)用相關(guān)觀察者的update 具體主題角色ConcreteSubject 實(shí)現(xiàn)抽象主題接口協(xié)議,當(dāng)狀態(tài)方式發(fā)生變化時(shí),對(duì)觀察者進(jìn)行通知 具體觀察者角色ConcreteObserver 實(shí)現(xiàn)抽象觀察者定義的接口,完成自身相關(guān)的同步更新活動(dòng)代碼示例
抽象觀察者角色,提供統(tǒng)一的更新方法 package observer; public interface Observer { void update(); } 抽象的Subject,內(nèi)部使用List<Observer>保存觀察者對(duì)象 提供了attach和dettach方法用于添加和刪除觀察者 并且提供了通知方法,就是遍歷調(diào)用Observer package observer; import java.util.LinkedList; import java.util.List;public abstract class Subject {List<Observer> observerList;Subject() {observerList = new LinkedList<>();}void attach(Observer o) {observerList.add(o);}void dettach(Observer o) {observerList.remove(o);}void notifyObservers() {for (Observer o : observerList) {o.update();}} } 具體的主題角色,他有一個(gè)行動(dòng)方法,行動(dòng)后通知其他的觀察者 觀察者在父類中列表里面定義 package observer; public class ConcreteSubject extends Subject {public void action() {System.out.println("下雨了");super.notifyObservers();} } 具體的觀察者,實(shí)現(xiàn)具體的行動(dòng) package observer; public class ConcreateObserver implements Observer {@Overridepublic void update() {System.out.println("那我收衣服了");} } 測(cè)試代碼 package observer; public class Test { public static void main(String[] args) {Observer o1 = new ConcreateObserver();ConcreteSubject subject = new ConcreteSubject();subject.attach(o1);subject.action();} }?
如果新增加一個(gè)觀察者 package observer; public class ConcreteObserver1 implements Observer {@Overridepublic void update() {System.out.println("那我得把窗戶關(guān)上");} }?
測(cè)試代碼 如上圖所示,有兩個(gè)觀察者(比如張三和李四),當(dāng)包租婆大喊一聲下雨了之后,他們都得到通知 張三去收衣服了,李四把自己的窗戶關(guān)上了 以上就是觀察者模式的簡(jiǎn)單示例。 觀察者模式的核心在于對(duì)于觀察者的管理和維護(hù),以及發(fā)送通知。 消息的發(fā)布訂閱,在程序中就是消息發(fā)布者調(diào)用訂閱者的相關(guān)方法 觀察者模式將發(fā)布者與訂閱者進(jìn)行解耦,不再是直接的方法調(diào)用,通過(guò)引入Observer角色,完成了發(fā)布者與具體訂閱者之間的解耦 也是一種形式的“方法調(diào)用”的解耦Java的觀察者模式
觀察者接口Observer是一個(gè)interface,定義了一個(gè)update方法
void update(Observable o, Object arg);
接受兩個(gè)參數(shù),一個(gè)是被觀察對(duì)象,一個(gè)是參數(shù) 被觀察角色Observerable 等同于前文Subject 內(nèi)部使用Vector維護(hù)觀察者Observer 提供了對(duì)觀察者的管理相關(guān)方法,添加、刪除、計(jì)算個(gè)數(shù)、刪除、刪除所有等 Observerable內(nèi)部使用標(biāo)志位記錄是否已經(jīng)發(fā)生變化 ??? private boolean changed = false; 發(fā)生變動(dòng)后,設(shè)置為true,通知后設(shè)置為false
| addObserver(Observer o) | 添加指定觀察者 |
| deleteObserver(Observer o)? | 刪除指定觀察者 |
| deleteObservers()????? | 刪除所有觀察者 |
| countObservers | 返回觀察者個(gè)數(shù) |
| notifyObservers() notifyObservers(Object arg)? | 通知所有觀察者 一個(gè)無(wú)參,一個(gè)有參 參數(shù)傳遞給Observer的update |
- 使用Vector保存觀察者,提供了添加、刪除、刪除全部的方法,并且可以返回觀察者的個(gè)數(shù)。
- 如果的確發(fā)生變動(dòng),將會(huì)通知所有的觀察者
?
package observer.java; import java.util.Observable; import java.util.Observer; public class Watcher1 implements Observer {@Overridepublic void update(Observable o, Object arg) {System.out.println("被觀察者:" + o + " ,參數(shù) " + arg + " ,觀察者1");} }?
?
package observer.java; import java.util.Observable; import java.util.Observer; public class Watcher2 implements Observer {@Overridepublic void update(Observable o, Object arg) {System.out.println("被觀察者:" + o + " ,參數(shù) " + arg + " ,觀察者2");} } Subject 繼承Observable類,自定義了changeState()方法 在方法中,調(diào)用 ??? setChanged(); ??? notifyObservers(); 完成狀態(tài)改變和通知。 從打印信息可以看得出來(lái) update方法接收到的第一個(gè)參數(shù),就是我們的被觀察者對(duì)象 第二個(gè)參數(shù)可以用來(lái)封裝傳遞信息 所以在java中,除非場(chǎng)景特殊,你又不需要自己寫觀察者模式了,已經(jīng)內(nèi)置了 通過(guò)繼承和實(shí)現(xiàn)相應(yīng)的類和接口即可。 GOF的設(shè)計(jì)模式出版于95,JDK 1.0始于1996,所以,Java天然支持某些設(shè)計(jì)模式也很正常 而且,設(shè)計(jì)模式是經(jīng)驗(yàn)總結(jié),GOF將他們歸納總結(jié)使之廣為人知,但是并不代表這些經(jīng)驗(yàn)史無(wú)前例 JDK的開(kāi)發(fā)者人家本身就有這些“經(jīng)驗(yàn)”也不足為奇。與中介者模式區(qū)別
觀察者模式用于一對(duì)多依賴場(chǎng)景中的解耦,通過(guò)引入Observer角色,將消息發(fā)布者與具體的訂閱者進(jìn)行解耦 中介者模式是將系統(tǒng)內(nèi)部多對(duì)多的復(fù)雜耦合關(guān)系,借助于中介者進(jìn)行解耦,將網(wǎng)狀結(jié)構(gòu),簡(jiǎn)化為星型結(jié)構(gòu),將多對(duì)多轉(zhuǎn)換為一對(duì)多? 他們都能夠?qū)崿F(xiàn)消息發(fā)布者與接收者的解耦,消息發(fā)布者都不知道具體的消息接收者 發(fā)起消息的Colleague同事類角色是被觀察者,中介類Mediator是觀察者,調(diào)用其他的同事類進(jìn)行協(xié)作 盡管觀察者模式強(qiáng)調(diào)“一致性通信” 中介者模式強(qiáng)調(diào)“內(nèi)部組件協(xié)作” 但是根本還是方法執(zhí)行時(shí),需要同步調(diào)用其他對(duì)象 兩個(gè)模式之間是一種類似的關(guān)系,在有些場(chǎng)景可替代轉(zhuǎn)換。 如果協(xié)作關(guān)系比較簡(jiǎn)單,可以實(shí)現(xiàn)為一對(duì)多的形式,使用觀察者模式 如果協(xié)作關(guān)系更加復(fù)雜,那么就可以使用中介者模式總結(jié)
觀察者模式是在一對(duì)多的依賴場(chǎng)景中,對(duì)消息發(fā)布者和消息訂閱者的解耦 在觀察者和被觀察者之間建立了一個(gè)抽象的耦合,而不是強(qiáng)關(guān)聯(lián) 通過(guò)引入觀察者角色,發(fā)布者不依賴具體的觀察者,從而Subject和Observer可以獨(dú)立發(fā)展 被觀察者僅僅知道有N個(gè)觀察者,他們以集合的形式被管理,都是Observer角色,但是完全不知道具體的觀察者 觀察者模式的支持廣播,被觀察者會(huì)向所有的觀察者發(fā)送消息。 增加新的觀察者時(shí),不需要修改客戶端代碼,只需要擴(kuò)展Observer接口即可,滿足開(kāi)閉原則。 一個(gè)觀察者,也可能是一個(gè)被觀察者,如果出現(xiàn)觀察者調(diào)用鏈,將會(huì)發(fā)生多米諾骨牌效應(yīng)不斷地進(jìn)行調(diào)用,后果可能是難以預(yù)知的。 所以要謹(jǐn)慎識(shí)別雙重身份的對(duì)象,也就是即是觀察者也是被觀察者的對(duì)象。 被觀察者不知道具體的觀察者,也更不可能知道觀察者具體的行為 當(dāng)發(fā)生狀態(tài)變化時(shí),被觀察者一個(gè)小舉動(dòng),可能引起很大的性能消耗,而被觀察者對(duì)此毫不知情,可能仍舊以為云淡風(fēng)輕。 當(dāng)一個(gè)對(duì)象狀態(tài)的改變,需要同時(shí)改變其他對(duì)象時(shí),可以考慮觀察者模式 當(dāng)一個(gè)對(duì)象必須通知其他人時(shí),但是他又不知道到底是誰(shuí)時(shí),可以考慮觀察者模式 或者將一個(gè)抽象模型中的兩個(gè)關(guān)聯(lián)部分解耦,以便獨(dú)立發(fā)展,提高復(fù)用性,解耦不表示斷開(kāi),仍舊需要聯(lián)系,可以借助于觀察者模式進(jìn)行聯(lián)系 總之 觀察模式通過(guò)引入觀察者角色,將調(diào)用者與被調(diào)用者解耦,通過(guò)觀察者角色聯(lián)系。 但凡類似“廣播”“發(fā)布訂閱”的場(chǎng)景,都可以考慮是否可用。 原文地址:觀察者模式 Observer 行為型 設(shè)計(jì)模式(二十三)轉(zhuǎn)載于:https://www.cnblogs.com/noteless/p/10147516.html
總結(jié)
以上是生活随笔為你收集整理的观察者模式 Observer 发布订阅模式 源 监听 行为型 设计模式(二十三)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: mysql学习【第10篇】:数据库之索引
- 下一篇: 极简模板语言实现