摘要:使用觀察者模式的好處支持簡單的廣播通信,自動通知所有已經訂閱過的對象。總的來說,觀察者模式所做的工作就是在解耦,讓耦合的雙方都依賴于抽象,而不是依賴于具體。
1. 介紹
觀察者模式又叫發布訂閱模式(Publish/Subscribe),它定義了一種一對多的關系,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象的狀態發生變化時就會通知所有的觀察者對象,使得它們能夠自動更新自己。
使用觀察者模式的好處:
支持簡單的廣播通信,自動通知所有已經訂閱過的對象。
目標對象與觀察者存在的是動態關聯,增加了靈活性。
目標對象與觀察者之間的抽象耦合關系能夠多帶帶擴展以及重用。
2. 實現一如下例子:
subscribers:含有不同 type 的數組,存儲有所有訂閱者的數組,訂閱行為將被加入到這個數組中
subscribe:方法為將訂閱者添加到 subscribers 中對應的數組中
unsubscribe:方法為在 subscribers 中刪除訂閱者
publish:循環遍歷 subscribers 中的每個元素,并調用他們注冊時提供的方法
let publisher = { subscribers: { any: [] }, subscribe: function(fn, type = "any") { if (typeof this.subscribers[type] === "undefined") { this.subscribers[type] = [] } this.subscribers[type].push(fn) }, unsubscribe: function(fn, type) { this.visitSubscribers("unsubscribe", fn, type) }, publish: function(publication, type) { this.visitSubscribers("publish", publication, type) }, visitSubscribers: function(action, arg, type = "any") { this.subscribers[type].forEach((currentValue, index, array) => { if (action === "publish") { currentValue(arg) } else if (action === "unsubscribe") { if (currentValue === arg) { this.subscribers[type].splice(index, 1) } } }) } } let funcA = function(cl) { console.log("msg1" + cl) } let funcB = function(cl) { console.log("msg2" + cl) } publisher.subscribe(funcA) publisher.subscribe(funcB) publisher.unsubscribe(funcB) publisher.publish(" in publisher") // msg1 in publisher
這里可以通過一個函數 makePublisher() 將一個對象復制成 publisher ,從而將其轉換成一個發布者。
function makePublisher(o) { Object.keys(publisher).forEach((curr, index, array) => { if (publisher.hasOwnProperty(curr) && typeof publisher[curr] === "function") { o[curr] = publisher[curr] } }) o.subscribers={any:[]} } // 發行者對象 let paper = { daily: function() { this.publish("big news today") }, monthly: function() { this.publish("interesting analysis", "monthly") } } makePublisher(paper) // 訂閱對象 let joe = { drinkCoffee: function(paper) { console.log("Just read daily " + paper) }, sundayPreNap: function(monthly) { console.log("Reading this monthly " + monthly) } } paper.subscribe(joe.drinkCoffee) paper.subscribe(joe.sundayPreNap, "monthly") paper.daily() // Just read daily big news today paper.monthly() // Reading this monthly interesting analysis3. 實現二
使用ES6里的class稍微改造下:
class publisher { constructor() { this.subscribers = { any: [] } } subscribe(fn, type = "any") { if (typeof this.subscribers[type] === "undefined") { this.subscribers[type] = [] } this.subscribers[type].push(fn) } unsubscribe(fn, type) { this.visitSubscribers("unsubscribe", fn, type) } publish(publication, type) { this.visitSubscribers("publish", publication, type) } visitSubscribers(action, arg, type = "any") { this.subscribers[type].forEach((currentValue, index, array) => { if (action === "publish") { currentValue(arg) } else if (action === "unsubscribe") { if (currentValue === arg) { this.subscribers[type].splice(index, 1) } } }) } } let publish = new publisher(); let funcA = function(cl) { console.log("msg1" + cl) } let funcB = function(cl) { console.log("msg2" + cl) } publish.subscribe(funcA) publish.subscribe(funcB) publish.unsubscribe(funcB) publish.publish(" in publisher") // msg1 in publisher4. 實現三
以上兩個方法都是《JavaScript模式》里介紹的,這里貼上個自己實現的,感覺看起來舒服點...
使用IIFE的方法:
const Observer = (function() { const _message = {} // 消息隊列 return { regist(type, fn) { // 訂閱 _message[type] ? _message[type].push(fn) : _message[type] = [fn] }, emit(type, payload) { // 發布 if (!_message[type]) { return } _message[type].forEach(event => event(payload)) }, remove(type, fn) { // 退訂 if (!_message[type].includes(fn)) {return} const idx = _message[type].indexOf(fn) _message[type].splice(idx, 1) } } })()
使用ES6的class方法
class Observer { constructor() { this._message = {} } regist(type, fn) { // 訂閱 this._message[type] ? this._message[type].push(fn) : this._message[type] = [fn] } emit(type, payload) { // 發布 if (!this._message[type]) { return } this._message[type].forEach(event => event(payload)) } remove(type, fn) { // 退訂 if (!this._message[type].includes(fn)) {return} const idx = this._message[type].indexOf(fn) this._message[type].splice(idx, 1) } }5. 總結
觀察者的使用場合就是:當一個對象的改變需要同時改變其它對象,并且它不知道具體有多少對象需要改變的時候,就應該考慮使用觀察者模式。
總的來說,觀察者模式所做的工作就是在解耦,讓耦合的雙方都依賴于抽象,而不是依賴于具體。從而使得各自的變化都不會影響到另一邊的變化。
本文是系列文章,可以相互參考印證,共同進步~
JS 抽象工廠模式
JS 工廠模式
JS 建造者模式
JS 原型模式
JS 單例模式
JS 回調模式
JS 外觀模式
JS 適配器模式
JS 利用高階函數實現函數緩存(備忘模式)
JS 狀態模式
JS 橋接模式
JS 觀察者模式
網上的帖子大多深淺不一,甚至有些前后矛盾,在下的文章都是學習過程中的總結,如果發現錯誤,歡迎留言指出~
參考:
設計模式之觀察者模式
《JavaScript模式》
《Javascript 設計模式》 - 張榮銘
PS:歡迎大家關注我的公眾號【前端下午茶】,一起加油吧~
另外可以加入「前端下午茶交流群」微信群,長按識別下面二維碼即可加我好友,備注加群,我拉你入群~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90348.html
摘要:觀察者模式定義設計模式中對的定義一個對象稱為維持一系列依賴于它觀察者的對象,將有關狀態的任何變更自動通知給它們。如圖模式比較觀察者模式則多了一個類似于話題調度中心的流程,發布者和訂閱者解耦。 Obeserver(觀察者)模式 定義 《js設計模式》中對Observer的定義:一個對象(稱為subject)維持一系列依賴于它(觀察者)的對象,將有關狀態的任何變更自動通知給它們。 《設計模...
摘要:觀察者模式對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更新。具體主題角色在具體主題內部狀態改變時,給所有登記過的觀察者發出通知。 觀察者模式 對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更新。 觀察者要素 1.抽象主題(Subject)角色:把所有對觀察者對象的引用保存在一個集合中,每個...
摘要:概念觀察者模式被廣泛地應用于客戶端編程中。所有的瀏覽器事件,等都是使用觀察者模式的例子。在觀察者模式中,一個對象訂閱另一個對象的指定活動并得到通知,而不是調用另一個對象的方法。此外,觀察者模式還可用于實現數據綁定。 概念 觀察者模式被廣泛地應用于JavaScript客戶端編程中。所有的瀏覽器事件(mouseover,keypress等)都是使用觀察者模式的例子。這種模式的另一個名字叫自...
摘要:期設計模式如何理解觀察者發布訂閱模式定義觀察者模式又叫發布訂閱模式,它定義了一種一對多的關系,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象的狀態發生變化時就會通知所有的觀察者對象,使得它們能夠自動更新自己生活實例理解你今天去看一個 20190411期 設計模式-如何理解觀察者(發布訂閱)模式? 定義: 觀察者模式又叫發布訂閱模式(Publish/Subscribe),它定義了一...
摘要:由主體和觀察者組成,主體負責發布事件,同時觀察者通過訂閱這些事件來觀察該主體。主體并不知道觀察者的任何事情,觀察者知道主體并能注冊事件的回調函數。總的來說,觀察者模式所做的工作就是在解耦,讓耦合的雙方都依賴于抽象,而不是依賴于具體。 發布訂閱模式 發布訂閱模式又叫觀察者模式(Publish/Subscribe),它定義了一種一對多的關系,讓多個觀察者對象同時監聽某一個主題對象,這個主題...
閱讀 2565·2021-10-11 10:58
閱讀 1148·2021-09-29 09:34
閱讀 1486·2021-09-26 09:46
閱讀 3830·2021-09-22 15:31
閱讀 730·2019-08-30 15:54
閱讀 1458·2019-08-30 13:20
閱讀 1251·2019-08-30 13:13
閱讀 1486·2019-08-26 13:52