成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

觀察者模式與發(fā)布/訂閱模式

tabalt / 1287人閱讀

摘要:觀察者模式與發(fā)布訂閱模式觀察者模式概念一個被觀察者的對象,通過注冊的方式維護一組觀察者對象。當被觀察者發(fā)生變化,就會產(chǎn)生一個通知,通過廣播的方式發(fā)送出去,最后調(diào)用每個觀察者的更新方法。

觀察者模式與發(fā)布/訂閱模式 觀察者模式 概念

一個被觀察者的對象,通過注冊的方式維護一組觀察者對象。當被觀察者發(fā)生變化,就會產(chǎn)生一個通知,通過廣播的方式發(fā)送出去,最后調(diào)用每個觀察者的更新方法。當觀察者不再需要接受被觀察者的通知時,被觀察者可以將該觀察者從所維護的組中刪除。

實現(xiàn)

這個實現(xiàn)包含以下組件:

被觀察者:維護一組觀察者, 提供用于增加和移除觀察者的方法

觀察者:提供一個更新接口,用于當被觀察者狀態(tài)變化時,得到通知

具體的被觀察者:狀態(tài)變化時廣播通知給觀察者,保持具體的觀察者的信息

具體的觀察者:保持一個指向具體被觀察者的引用,實現(xiàn)一個更新接口,用于觀察,以便保證自身狀態(tài)總是和被觀察者狀態(tài)一致的

首先,對被觀察者維護的一組觀察者(列表)進行建模

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 函數(shù)之后會被具體的行為覆蓋

function Observer() {
  this.update = function() {
    // ...
  }
}

樣例應(yīng)用

我們使用上面的觀察者組件,現(xiàn)在我們定義

一個按鈕,這個按鈕用于增加新的充當觀察者的選擇框到頁面上

一個控制用的選擇框 , 充當一個被觀察者,通知其它選擇框是否應(yīng)該被選中

一個容器,用于放置新的選擇框



// DOM 元素的引用
var controlCheckbox = document.getElementById("mainCheckbox"),
  addBtn = document.getElementById("addNewObserver"),
  container = document.getElementById("observersContainer")

// 具體的被觀察者

// Subject 類擴展 controlCheckbox
extend(new Subject(), controlCheckbox)

//點擊 checkbox 將會觸發(fā)對觀察者的通知
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 函數(shù)重載
  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,調(diào)用了被觀察者的 notify 方法,進而觸發(fā)了 controlCheckbox 中所維護的觀察者的 update 方法

發(fā)布/訂閱模式 實現(xiàn)
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)
樣例應(yīng)用 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: "[email protected]",
  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?")
樣例應(yīng)用 2

舊的代碼

$.ajax("http:// xxx.com?login", function(data) {
  header.setAvatar(data.avatar) // 設(shè)置 header 模塊的頭像
  nav.setAvatar(data.avatar) // 設(shè)置導航模塊的頭像
})

使用了發(fā)布/訂閱模式的代碼

$.ajax("http:// xxx.com?login", function(data) {
  pubsub.publish("loginSucc", data) // 發(fā)布登錄成功的消息
})

// header 模塊
var header = (function() {
  pubsub.subscribe("loginSucc", function(data) {
    header.setAvatar(data.avatar)
  })

  return {
    setAvatar: function(data) {
      console.log("設(shè)置 header 模塊的頭像")
    }
  }
})()

// nav 模塊
var nav = (function() {
  pubsub.subscribe("loginSucc", function(data) {
    nav.setAvatar(data.avatar)
  })

  return {
    setAvatar: function(avatar) {
      console.log("設(shè)置 nav 模塊的頭像")
    }
  }
})()
優(yōu)點

可以應(yīng)用于異步編程中,比如 ajax 請求的 succ、error 等事件中,或者動畫的每一幀完成之后去發(fā)布一個事件,從而不需要過多關(guān)注對象再異步運行期間的內(nèi)部狀態(tài)

取代對象之間硬編碼的通知機制,一個對象不再顯示地調(diào)用另外一個對象的某個接口,讓這兩個對象松耦合的聯(lián)系在一起

缺點

創(chuàng)建訂閱者需消耗一定內(nèi)存,當你訂閱一個消息后,即使消息直到最后都未發(fā)生,但這個訂閱者也會始終存在于內(nèi)存中

發(fā)布/訂閱模式弱化對象之間的聯(lián)系,對象和對象之間的必要聯(lián)系也被深埋在背后,導致程序難以跟蹤維護和理解

二者的不同

觀察者模式要求想要接受相關(guān)通知的觀察者必須到發(fā)起這個事件的被觀察者上注冊這個事件

controlCheckbox.AddObserver(check)

發(fā)布/訂閱模式使用一個主題/事件頻道,這個頻道處于訂閱者和發(fā)布者之間,這個事件系統(tǒng)允許代碼定義應(yīng)用相關(guān)的事件,避免訂閱者和發(fā)布者之間的依賴性

pubsub.subscribe("inbox/newMessage", messageLogger)
pubsub.publish("inbox/newMessage", "hello world!")

參考資料

《JavaScript設(shè)計模式》 作者:Addy Osmani

《JavaScript設(shè)計模式與開發(fā)實踐》 作者:曾探

設(shè)計模式(三):觀察者模式與發(fā)布/訂閱模式區(qū)別

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/109522.html

相關(guān)文章

  • 設(shè)計模式察者模式發(fā)布訂閱模式

    摘要:觀察者模式與發(fā)布訂閱的區(qū)別在模式中,知道,同時還保留了的記錄。發(fā)布者訂閱者在大多情況下是異步方式使用消息隊列。圖片源于網(wǎng)絡(luò)侵權(quán)必刪如果以結(jié)構(gòu)來分辨模式,發(fā)布訂閱模式相比觀察者模式多了一個中間件訂閱器,所以發(fā)布訂閱模式是不同于觀察者模式的。 學習了一段時間設(shè)計模式,當學到觀察者模式和發(fā)布訂閱模式的時候遇到了很大的問題,這兩個模式有點類似,有點傻傻分不清楚,博客起因如此,開始對觀察者和發(fā)布...

    BaronZhang 評論0 收藏0
  • 發(fā)布訂閱模式實現(xiàn)及發(fā)布訂閱模式察者模式的不同

    摘要:發(fā)布訂閱者模式中,訂閱者是不知道也不關(guān)心事件是為什么觸發(fā),是由哪一個事件觸發(fā),只知道事件觸發(fā)時候,會告訴自己。然而,在發(fā)布訂閱模式中,發(fā)布者和訂閱者不知道對方的存在。在發(fā)布訂閱模式中,組件是松散耦合的,正好和觀察者模式相反。 概念 發(fā)布訂閱者模式,是javascript甚至大多數(shù)語言都有的語言模式,比較概念的解釋是, 訂閱者把自己想訂閱的事件注冊到調(diào)度中心,當該事件觸發(fā)時候,發(fā)布者發(fā)布...

    YanceyOfficial 評論0 收藏0
  • 發(fā)布訂閱模式實現(xiàn)及發(fā)布訂閱模式察者模式的不同

    摘要:發(fā)布訂閱者模式中,訂閱者是不知道也不關(guān)心事件是為什么觸發(fā),是由哪一個事件觸發(fā),只知道事件觸發(fā)時候,會告訴自己。然而,在發(fā)布訂閱模式中,發(fā)布者和訂閱者不知道對方的存在。在發(fā)布訂閱模式中,組件是松散耦合的,正好和觀察者模式相反。 概念 發(fā)布訂閱者模式,是javascript甚至大多數(shù)語言都有的語言模式,比較概念的解釋是, 訂閱者把自己想訂閱的事件注冊到調(diào)度中心,當該事件觸發(fā)時候,發(fā)布者發(fā)布...

    Jensen 評論0 收藏0
  • JavaScript 設(shè)計模式(六):察者模式發(fā)布訂閱模式

    摘要:觀察者模式維護單一事件對應(yīng)多個依賴該事件的對象關(guān)系發(fā)布訂閱維護多個事件主題及依賴各事件主題的對象之間的關(guān)系觀察者模式是目標對象直接觸發(fā)通知全部通知,觀察對象被迫接收通知。 觀察者模式(Observer) 觀察者模式:定義了對象間一種一對多的依賴關(guān)系,當目標對象 Subject 的狀態(tài)發(fā)生改變時,所有依賴它的對象 Observer 都會得到通知。 簡單點:女神有男朋友了,朋友圈曬個圖,甜...

    bingo 評論0 收藏0
  • 察者模式發(fā)布-訂閱模式

    摘要:觀察者模式觀察者模式一個對象主體根據(jù)它維護的一個對象列表觀察者,自動通知它們狀態(tài)的任何變化。觀察者模式是由具體目標直接調(diào)度的操作而發(fā)布訂閱模式是在調(diào)度中心調(diào)度,發(fā)布者與訂閱者不產(chǎn)生依賴。 觀察者模式(Observer) 觀察者模式:一個對象(主體)根據(jù)它維護的一個對象列表(觀察者),自動通知它們狀態(tài)的任何變化。(舉例說明,電商平臺關(guān)注(訂閱)一家店鋪(發(fā)布者)的鞋子,當鞋子上架之后店鋪...

    劉東 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<