摘要:發布訂閱模式又叫觀察者模式,它定義對象間的一種一對多的依賴關系。事件觀察者模式應該是最常用的模式之一。總之,當消息一發布,所有的訂閱者都會收到消息。發布訂閱模式還可以用來幫助實現一些別的設計模式,比如中介者模式。
發布/訂閱模式又叫觀察者模式,它定義對象間的一種一對多的依賴關系。當一個對象的狀態(發布者)發生改變時,所有依賴于它的對象都將得到通知。在 JavaScript 開發中,我們一般用事件模型來替代傳統的發布—訂閱模式。
DOM 事件觀察者模式應該是最常用的模式之一。在很多語言里都得到大量應用。包括我們平時接觸的dom事件,也是js和dom之間實現的一種觀察者模式。
document.body.addEventListener("click",function () { alert(111); },false); document.body.addEventListener("click",function () { alert(222); },false); document.body.addEventListener("click",function () { alert(333); },false); document.body.click();//模擬點擊事件
這里我們訂閱了document.body 的 click 事件,當 body 被點擊的時候,他就向訂閱者發布這個消息,順序彈出111 222 333。我們也可以隨意的增加和刪除訂閱者。總之,當消息一發布,所有的訂閱者都會收到消息。
這里,手動觸發事件直接用了document.body.click();但是更好的做法是IE下用 fireEvent,標準瀏覽器下用 dispatchEvent。
全局的發布/訂閱對象發布/訂閱模式可以用一個全局的 Event 對象來實現,訂閱者不需要了解消息來自哪個發布者,發布者也不知道消息會推送給哪些訂閱者,Event 作為一個類似“中介者” 的角色,把訂閱者和發布者聯系起來。
let Event = (function () { let clientList = {}; let listen; let trigger; let remove; listen = function (name, cb) { if( !clientList[name] ) { clientList[name] = []; } clientList[name].push(cb); }; trigger = function () { let name = [].shift.call(arguments); let fns = clientList[name]; if( !fns || fns.length == 0 ) return false; fns.map((item, index) => { item(...arguments); // 不要直接將arguments傳入 }) }; remove = function (name, cb) { let fns = clientList[name]; if( !fns ) return false; // name對應的消息么有被人訂閱 if( !cb ) { // 沒有傳入cb(具體的回調函數), 表示取消 name 對應的所有訂閱 fns && (fns.length = 0); // 不加括號會報錯:ReferenceError: Invalid left-hand side in assignment } else { clientList[name] = fns.filter((item, index) => { return item !== cb; // filter不改變原數組 return不忘記 }) /* // 反向遍歷 for(let i = fns.length - 1; i >= 0; i--) { let _cb = fns[i]; if(_cb === cb) { fns.splice(i, 1); } } */ } }; return { listen: listen, trigger: trigger, remove: remove } })(); let foo1 = function( num ){ console.log("foo triggered"); } let foo2 = function( num ){ console.log(num); } Event.listen("foo", foo1); Event.listen("foo", foo2); Event.trigger("foo", 2); // foo triggered // 2
看下下面這段代碼的輸出,可以看到是無法取消對應的訂閱信息的。就像{} === {}結果是 false一樣(引用類型的特點:按地址存放)。
Event.remove("foo", function(num){console.log(num)}); Event.trigger("foo", 2); // let obj1 = {}; // let obj2 = {}; //obj1 === obj2 // false //but //obj1 === obj1 // true
正確寫法:
Event.remove("foo", foo2); Event.trigger("foo", 2);必須先訂閱再發布嗎
我們所了解的發布/訂閱模式,都是訂閱者必須先訂閱一個消息,隨后才能接收到發布者發布的消息。如果把順序反過來,發布者先發布一個消息,而在此之前并沒有對象來訂閱它,那么這條消息就消失在宇宙中了。
建立一個存放離線事件的堆棧,當事件發布的時候,如果此時還沒有訂閱者來訂閱這個事件,我們暫時把發布事件的動作包裹在一個函數里,這些包裝函數將被存入堆棧中,等到終于有對象來訂閱此事件的時候,我們將遍歷堆棧并且依次執行這些包裝函數,也就是重新發布里面的事件。當然離線事件的生命周期只有一次,就像QQ的未讀消息只會被重 新閱讀一次,所以剛才的操作我們只能進行一次。
優缺點優點:
發布—訂閱模式的優點非常明顯:
時間上的解耦;
對象之間的解耦。
它的應用非常廣泛,既可以用在異步編程中,也可以幫助我們完成更松耦合的代碼編寫。發布/訂閱模式還可以用來幫助實現一些別的設計模式,比如中介者模式。
從架構上來看,無論是 MVC 還是 MVVM,,都少不了發布/訂閱模式的參與,而且 JavaScript 本身也是一門基于事件驅動的語言。
缺點:
當然,發布/訂閱模式也不是完全沒有缺點。創建訂閱者本身要消耗一定的時間和內存,而且當你訂閱一個消息后,也許此消息最后都未發生,但這個訂閱者會始終存在于內存中。
另外,發布/訂閱模式雖然可以弱化對象之間的聯系,但如果過度使用的話,對象和對象之間的必要聯系也將被深埋在背后,會導致程序難以跟蹤維護和理解。特別是有多個發布者和訂閱者嵌套到一起的時候,要跟蹤一個 bug 不是件輕松的事情。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97239.html
摘要:設計模式與開發實踐讀書筆記。發布訂閱模式又叫觀察者模式,它定義了對象之間的一種一對多的依賴關系。附設計模式之發布訂閱模式觀察者模式數據結構和算法系列棧隊列優先隊列循環隊列設計模式系列設計模式之策略模式 《JavaScript設計模式與開發實踐》讀書筆記。 發布-訂閱模式又叫觀察者模式,它定義了對象之間的一種一對多的依賴關系。當一個對象的狀態發生改變時,所有依賴它的對象都將得到通知。 例...
摘要:觀察者模式與發布訂閱的區別在模式中,知道,同時還保留了的記錄。發布者訂閱者在大多情況下是異步方式使用消息隊列。圖片源于網絡侵權必刪如果以結構來分辨模式,發布訂閱模式相比觀察者模式多了一個中間件訂閱器,所以發布訂閱模式是不同于觀察者模式的。 學習了一段時間設計模式,當學到觀察者模式和發布訂閱模式的時候遇到了很大的問題,這兩個模式有點類似,有點傻傻分不清楚,博客起因如此,開始對觀察者和發布...
摘要:觀察者模式定義設計模式中對的定義一個對象稱為維持一系列依賴于它觀察者的對象,將有關狀態的任何變更自動通知給它們。如圖模式比較觀察者模式則多了一個類似于話題調度中心的流程,發布者和訂閱者解耦。 Obeserver(觀察者)模式 定義 《js設計模式》中對Observer的定義:一個對象(稱為subject)維持一系列依賴于它(觀察者)的對象,將有關狀態的任何變更自動通知給它們。 《設計模...
摘要:設計模式與開發實踐讀書筆記。看此文章前,建議先看設計模式之發布訂閱模式觀察者模式在中,已經介紹了什么是發布訂閱模式,同時,也實現了發布訂閱模式。 《JavaScript設計模式與開發實踐》讀書筆記。 看此文章前,建議先看JavaScript設計模式之發布-訂閱模式(觀察者模式)-Part1 在Part1中,已經介紹了什么是發布-訂閱模式,同時,也實現了發布-訂閱模式。但是,就Part1...
閱讀 786·2021-08-23 09:46
閱讀 928·2019-08-30 15:44
閱讀 2586·2019-08-30 13:53
閱讀 3039·2019-08-29 12:48
閱讀 3847·2019-08-26 13:46
閱讀 1780·2019-08-26 13:36
閱讀 3510·2019-08-26 11:46
閱讀 1408·2019-08-26 10:48