前言
準備研究一下MVVM的一些東西,由于MVVM運用了觀察者模式的思想,因此翻開了《JavaScript設計模式與開發(fā)實踐》一書,將觀察者模式學習了一遍,順便有對一些常用的設計模式進行一些了解,但還是有很多不能理解的地方,還需努力啊。
一、什么是觀察者模式
觀察者模式又叫做發(fā)布—訂閱模式,是我們最常用的設計模式之一。它定義對象間的一種一對多的依賴關系,當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都將得到通知和更新。觀察者模式提供了一個訂閱模型,其中對象訂閱事件并在發(fā)生時得到通知,這種模式是事件驅動的編程基石,它有利益于良好的面向對象的設計。
看了上面的這段描述,可能還是不懂什么是觀察者模式。我們還可以來看看生活中的觀察者模式:現在房價這么高,你肯定是想要早點買房,但你看好的樓盤還沒開盤,因此你就將你的電話留給售樓小姐,一旦樓盤推出就讓她打電話給你。主動權在售樓方,而你只需要提供一個聯系方式就行了這樣你就不用擔心樓盤出來你不知道了,也不需要每天都打電話去問樓盤推出了沒。
二、觀察者模式的使用場景
2.1 DOM事件
實際上,只要我們曾經在DOM節(jié)點上面綁定過事件函數,那我們就使用過觀察者模式,應為JS和DOM之間就是實現了一種觀察者模式。
document.body.addEventListener("click", function() {
alert("Hello World")
},false )
document.body.click() //模擬用戶點擊
在上面的代碼中,需要監(jiān)聽用戶點擊 document.body 的動作,但是我們是沒辦法預知用戶將在什么時候點擊的。因此我們訂閱了 document.body 的 click 事件,當 body 節(jié)點被點擊時,body 節(jié)點便會向訂閱者發(fā)布 "Hello World" 消息。
2.2自定義事件
除了DOM事件外,我們還可以實現一些自定義事件,這種依靠自定義時間完成的觀察者模式可以用于任何的JavaScript代碼中。
示例:
const event = {
clientList: [],
listen: function(key , fn) {
if (this.clientListen[key]) {
this.clientList[key] = []
}
this.clientList[key].push(fn)
},
trigger: function() {
const key = Array.prototype.shift.call(arguments)
const fns = this.clientList[key]
if (!fns || fns.length === 0 ) {
return false
}
for (let i = 0, fn ;fn = fns[i++];) {
fn.apply(this, arguments)
}
},
remove : function(key , fn) {
const fns = this.clientList[key]
if (!fns) {
return false
}
if (!fn) {
fns && (fns.length = 0)
} else {
for (let l = fns.length - 1; l>=0; l--) {
const _fn = fns[l]
if ( _fn ===fn) {
fns.splice(l, 1)
}
}
}
}
const installEvent = (obj) => {
for (let i in event) {
obj[i] = event[i]
}
}
然后就能增加發(fā)布和訂閱功能了:
const events = {}
installEvent(events)
// 訂閱信息
events.listen('newMessage',fn1 = (say) => {
console.log('say:' + say)
})
// 發(fā)布信息
events.trigger('newMessage',"Hello world")
//移除訂閱
events.remove('newMessage',fn1)
三、觀察者模式的不足
觀察者模式的有點非常明顯:一是時間上的解耦,而是對象之間的解耦。既可用于異步編程中,也可以用幫助我們完成更松耦合的代碼編寫。但它仍然有所不足:
- 創(chuàng)建訂閱者本身要消耗一定的時間和內存
- 當訂閱一個消息時,也許此消息并沒有發(fā)生,但這個訂閱者會始終存在內存中。
- 觀察者模式弱化了對象之間的聯系,這本是好事情,但如果過度使用,對象與對象之間的聯系也會被隱藏的很深,會導致項目的難以跟蹤維護和理解。