摘要:觀察者模式與發布訂閱模式觀察者模式概念一個被觀察者的對象,通過注冊的方式維護一組觀察者對象。當被觀察者發生變化,就會產生一個通知,通過廣播的方式發送出去,最后調用每個觀察者的更新方法。
觀察者模式與發布/訂閱模式 觀察者模式 概念
一個被觀察者的對象,通過注冊的方式維護一組觀察者對象。當被觀察者發生變化,就會產生一個通知,通過廣播的方式發送出去,最后調用每個觀察者的更新方法。當觀察者不再需要接受被觀察者的通知時,被觀察者可以將該觀察者從所維護的組中刪除。
實現這個實現包含以下組件:
被觀察者:維護一組觀察者, 提供用于增加和移除觀察者的方法
觀察者:提供一個更新接口,用于當被觀察者狀態變化時,得到通知
具體的被觀察者:狀態變化時廣播通知給觀察者,保持具體的觀察者的信息
具體的觀察者:保持一個指向具體被觀察者的引用,實現一個更新接口,用于觀察,以便保證自身狀態總是和被觀察者狀態一致的
首先,對被觀察者維護的一組觀察者(列表)進行建模
function ObserverList() { this.observerList = [] } ObserverList.prototype.add = function(obj) { return this.observerList.push(obj) } ObserverList.prototype.Empty = function() { this.observerList = [] } ObserverList.prototype.removeAt = function(index) { this.observerList.splice(index, 1) } ObserverList.prototype.count = function() { return this.observerList.length } ObserverList.prototype.get = function(index) { if (index > -1 && index < this.observerList.length) { return this.observerList[index] } } // Extend an object with an extension function extend(extension, obj) { for (var key in extension) { obj[key] = extension[key] } }
接著,對被觀察者以及其增加、刪除、通知能力進行建模
function Subject() { this.observers = new ObserverList() } Subject.prototype.addObserver = function(observer) { this.observers.add(observer) } Subject.prototype.removeObserver = function(observer) { this.observers.removeAt(this.observers.IndexOf(observer, 0)) } Subject.prototype.notify = function(context) { var observerCount = this.observers.count() for (var i = 0; i < observerCount; i++) { this.observers.get(i).update(context) } }
接著,對觀察者進行建模,這里的 update 函數之后會被具體的行為覆蓋
function Observer() { this.update = function() { // ... } }樣例應用
我們使用上面的觀察者組件,現在我們定義
一個按鈕,這個按鈕用于增加新的充當觀察者的選擇框到頁面上
一個控制用的選擇框 , 充當一個被觀察者,通知其它選擇框是否應該被選中
一個容器,用于放置新的選擇框
// DOM 元素的引用 var controlCheckbox = document.getElementById("mainCheckbox"), addBtn = document.getElementById("addNewObserver"), container = document.getElementById("observersContainer") // 具體的被觀察者 // Subject 類擴展 controlCheckbox extend(new Subject(), controlCheckbox) //點擊 checkbox 將會觸發對觀察者的通知 controlCheckbox["onclick"] = new Function( "controlCheckbox.notify(controlCheckbox.checked)" ) addBtn["onclick"] = AddNewObserver // 具體的觀察者 function AddNewObserver() { // 建立一個新的用于增加的 checkbox var check = document.createElement("input") check.type = "checkbox" // 使用 Observer 類擴展 checkbox extend(new Observer(), check) // 使用定制的 update 函數重載 check.update = function(value) { this.checked = value } // 增加新的觀察者到我們主要的被觀察者的觀察者列表中 controlCheckbox.AddObserver(check) // 將元素添加到容器的最后 container.appendChild(check) }
上述示例中
Subject 類擴展 controlCheckbox,所以 controlCheckbox 是具體的被觀察者
點擊 addBtn 時,生成一個新的 check,check 被 Observer 類所拓展并重寫了 update 方法,所以 check 是具體的觀察者,最后 controlCheckbox 將 check 添加到了 controlCheckbox 所維護的觀察者列表中
點擊 controlCheckbox,調用了被觀察者的 notify 方法,進而觸發了 controlCheckbox 中所維護的觀察者的 update 方法
發布/訂閱模式 實現var pubsub = {} ;(function(q) { var topics = {}, subUid = -1 // Publish or broadcast events of interest // with a specific topic name and arguments // such as the data to pass along q.publish = function(topic, args) { if (!topics[topic]) { return false } var subscribers = topics[topic], len = subscribers ? subscribers.length : 0 while (len--) { subscribers[len].func(topic, args) } return this } // Subscribe to events of interest // with a specific topic name and a // callback function, to be executed // when the topic/event is observed q.subscribe = function(topic, func) { if (!topics[topic]) { topics[topic] = [] } var token = (++subUid).toString() topics[topic].push({ token: token, func: func }) return token } // Unsubscribe from a specific // topic, based on a tokenized reference // to the subscription q.unsubscribe = function(token) { for (var m in topics) { if (topics[m]) { for (var i = 0, j = topics[m].length; i < j; i++) { if (topics[m][i].token === token) { topics[m].splice(i, 1) return token } } } } return this } })(pubsub)樣例應用 1
// Another simple message handler // A simple message logger that logs any topics and data received through our // subscriber var messageLogger = function(topics, data) { console.log("Logging: " + topics + ": " + data) } // Subscribers listen for topics they have subscribed to and // invoke a callback function (e.g messageLogger) once a new // notification is broadcast on that topic var subscription = pubsub.subscribe("inbox/newMessage", messageLogger) // Publishers are in charge of publishing topics or notifications of // interest to the application. e.g: pubsub.publish("inbox/newMessage", "hello world!") // or pubsub.publish("inbox/newMessage", ["test", "a", "b", "c"]) // or pubsub.publish("inbox/newMessage", { sender: "hello@google.com", body: "Hey again!" }) // We cab also unsubscribe if we no longer wish for our subscribers // to be notified // pubsub.unsubscribe( subscription ); // Once unsubscribed, this for example won"t result in our // messageLogger being executed as the subscriber is // no longer listening pubsub.publish("inbox/newMessage", "Hello! are you still there?")樣例應用 2
舊的代碼
$.ajax("http:// xxx.com?login", function(data) { header.setAvatar(data.avatar) // 設置 header 模塊的頭像 nav.setAvatar(data.avatar) // 設置導航模塊的頭像 })
使用了發布/訂閱模式的代碼
$.ajax("http:// xxx.com?login", function(data) { pubsub.publish("loginSucc", data) // 發布登錄成功的消息 }) // header 模塊 var header = (function() { pubsub.subscribe("loginSucc", function(data) { header.setAvatar(data.avatar) }) return { setAvatar: function(data) { console.log("設置 header 模塊的頭像") } } })() // nav 模塊 var nav = (function() { pubsub.subscribe("loginSucc", function(data) { nav.setAvatar(data.avatar) }) return { setAvatar: function(avatar) { console.log("設置 nav 模塊的頭像") } } })()優點
可以應用于異步編程中,比如 ajax 請求的 succ、error 等事件中,或者動畫的每一幀完成之后去發布一個事件,從而不需要過多關注對象再異步運行期間的內部狀態
取代對象之間硬編碼的通知機制,一個對象不再顯示地調用另外一個對象的某個接口,讓這兩個對象松耦合的聯系在一起
缺點創建訂閱者需消耗一定內存,當你訂閱一個消息后,即使消息直到最后都未發生,但這個訂閱者也會始終存在于內存中
發布/訂閱模式弱化對象之間的聯系,對象和對象之間的必要聯系也被深埋在背后,導致程序難以跟蹤維護和理解
二者的不同
觀察者模式要求想要接受相關通知的觀察者必須到發起這個事件的被觀察者上注冊這個事件
controlCheckbox.AddObserver(check)
發布/訂閱模式使用一個主題/事件頻道,這個頻道處于訂閱者和發布者之間,這個事件系統允許代碼定義應用相關的事件,避免訂閱者和發布者之間的依賴性
pubsub.subscribe("inbox/newMessage", messageLogger) pubsub.publish("inbox/newMessage", "hello world!")參考資料
《JavaScript設計模式》 作者:Addy Osmani
《JavaScript設計模式與開發實踐》 作者:曾探
設計模式(三):觀察者模式與發布/訂閱模式區別
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109522.html
摘要:觀察者模式與發布訂閱的區別在模式中,知道,同時還保留了的記錄。發布者訂閱者在大多情況下是異步方式使用消息隊列。圖片源于網絡侵權必刪如果以結構來分辨模式,發布訂閱模式相比觀察者模式多了一個中間件訂閱器,所以發布訂閱模式是不同于觀察者模式的。 學習了一段時間設計模式,當學到觀察者模式和發布訂閱模式的時候遇到了很大的問題,這兩個模式有點類似,有點傻傻分不清楚,博客起因如此,開始對觀察者和發布...
摘要:發布訂閱者模式中,訂閱者是不知道也不關心事件是為什么觸發,是由哪一個事件觸發,只知道事件觸發時候,會告訴自己。然而,在發布訂閱模式中,發布者和訂閱者不知道對方的存在。在發布訂閱模式中,組件是松散耦合的,正好和觀察者模式相反。 概念 發布訂閱者模式,是javascript甚至大多數語言都有的語言模式,比較概念的解釋是, 訂閱者把自己想訂閱的事件注冊到調度中心,當該事件觸發時候,發布者發布...
摘要:發布訂閱者模式中,訂閱者是不知道也不關心事件是為什么觸發,是由哪一個事件觸發,只知道事件觸發時候,會告訴自己。然而,在發布訂閱模式中,發布者和訂閱者不知道對方的存在。在發布訂閱模式中,組件是松散耦合的,正好和觀察者模式相反。 概念 發布訂閱者模式,是javascript甚至大多數語言都有的語言模式,比較概念的解釋是, 訂閱者把自己想訂閱的事件注冊到調度中心,當該事件觸發時候,發布者發布...
摘要:觀察者模式維護單一事件對應多個依賴該事件的對象關系發布訂閱維護多個事件主題及依賴各事件主題的對象之間的關系觀察者模式是目標對象直接觸發通知全部通知,觀察對象被迫接收通知。 觀察者模式(Observer) 觀察者模式:定義了對象間一種一對多的依賴關系,當目標對象 Subject 的狀態發生改變時,所有依賴它的對象 Observer 都會得到通知。 簡單點:女神有男朋友了,朋友圈曬個圖,甜...
摘要:觀察者模式觀察者模式一個對象主體根據它維護的一個對象列表觀察者,自動通知它們狀態的任何變化。觀察者模式是由具體目標直接調度的操作而發布訂閱模式是在調度中心調度,發布者與訂閱者不產生依賴。 觀察者模式(Observer) 觀察者模式:一個對象(主體)根據它維護的一個對象列表(觀察者),自動通知它們狀態的任何變化。(舉例說明,電商平臺關注(訂閱)一家店鋪(發布者)的鞋子,當鞋子上架之后店鋪...
閱讀 1228·2021-09-26 09:46
閱讀 1582·2021-09-06 15:00
閱讀 713·2019-08-30 15:52
閱讀 1116·2019-08-29 13:10
閱讀 1277·2019-08-26 13:47
閱讀 1479·2019-08-26 13:35
閱讀 2027·2019-08-23 18:38
閱讀 721·2019-08-23 17:59