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