有這么一段代碼經(jīng)常會(huì)出現(xiàn)在代碼中
var pubsub = (()=>{
var topics = {};
function subscribe(topic,fn){
if(!topics[topic]){
topics[topic] = [];
}
topics[topic].push(fn);
}
function publish(topic,...args){
if(!topics[topic])
return;
for(let fn of topics[topic]){
fn(...args);
}
}
return {
subscribe,
publish
}
})()
測(cè)試代碼
pubsub.subscribe('test',function(a,b){ //訂閱者A訂閱了test事件
console.log(a,b);
});
pubsub.publish('test','123','HH'); //123 HH(發(fā)布者B發(fā)布了test事件)
調(diào)用publish后打印出了123 HH济欢。很奇妙的一段代碼,當(dāng)然實(shí)際上只是遍歷了數(shù)組跌前,然后把數(shù)組中的所有函數(shù)全部執(zhí)行一遍而已雀瓢。但是對(duì)于一個(gè)沒(méi)讀過(guò)實(shí)現(xiàn)代碼的人來(lái)說(shuō),卻是一個(gè)神奇的存在种玛,JS居然能訂閱發(fā)布消息藐鹤,太酷了瓤檐。
有的時(shí)候我會(huì)叫他觀察者模式赂韵,有時(shí)候又會(huì)叫他發(fā)布訂閱模式,覺(jué)得叫什么都是對(duì)的挠蛉。
但是祭示,他們并不一樣。
差異
在觀察者模式中谴古,觀察者需要直接訂閱目標(biāo)事件质涛。在目標(biāo)發(fā)出內(nèi)容改變的事件后,直接接收事件并作出響應(yīng)掰担。發(fā)布訂閱模式相比觀察者模式多了個(gè)事件通道汇陆,訂閱者和發(fā)布者不是直接關(guān)聯(lián)的。
這段話可以看出上面的例子是發(fā)布訂閱模式带饱。訂閱者A和發(fā)布者B是通過(guò)pubsub這個(gè)對(duì)象關(guān)聯(lián)起來(lái)的毡代,他們沒(méi)有直接的交流。
那么真正的觀察者模式是怎么樣的勺疼?
一個(gè)或多個(gè)觀察者對(duì)目標(biāo)的狀態(tài)感興趣教寂,通過(guò)將自己依附在目標(biāo)對(duì)象上以便注冊(cè)所感興趣的內(nèi)容。目標(biāo)狀態(tài)發(fā)生改變并且觀察者可能對(duì)這些改變感興趣执庐,會(huì)發(fā)送一個(gè)通知消息酪耕,調(diào)用每個(gè)觀察者的更新方法。當(dāng)觀察者不再對(duì)目標(biāo)狀態(tài)感興趣時(shí)轨淌,他們可以簡(jiǎn)單將自己從中分離迂烁。
我們來(lái)實(shí)現(xiàn)下觀察者模式看尼。首先是目標(biāo)的構(gòu)造函數(shù),他有個(gè)數(shù)組盟步,用于添加觀察者狡忙。還有個(gè)廣播方法,遍歷觀察者數(shù)組后調(diào)用他們的update方法:
class Subject{
constructor(){
this.subs = [];
}
addSub(sub){
this.subs.push(sub);
}
notify(){
this.subs.forEach(sub=> {
sub.update();
});
}
}
那么觀察者就得有個(gè)update方法:
class Observer{
update(){
console.log('update');
}
}
測(cè)試代碼
let subject = new Subject();
let ob = new Observer();
//目標(biāo)添加觀察者了
subject.addSub(ob);
//目標(biāo)發(fā)布消息調(diào)用觀察者的更新方法了
subject.notify(); //update
可以看到目標(biāo)和觀察者是直接聯(lián)系在一起的址芯。觀察者把自身添加到了目標(biāo)對(duì)象中灾茁,可見(jiàn)和發(fā)布訂閱模式差別還是很大的。在這種模式下谷炸,目標(biāo)更像一個(gè)發(fā)布者北专,他讓添加進(jìn)來(lái)的所有觀察者都執(zhí)行了update函數(shù),而觀察者就像一個(gè)訂閱者旬陡。
優(yōu)劣
個(gè)人覺(jué)得發(fā)布/訂閱模式比較簡(jiǎn)單拓颓,使用的也比較廣泛。由于他訂閱者和發(fā)布者不直接關(guān)聯(lián)的特點(diǎn)我們完全可以把管理事件的對(duì)象寫到一個(gè)單獨(dú)文件中描孟,作為庫(kù)來(lái)使用驶睦。發(fā)布訂閱模式中,雙方不知道對(duì)方的存在匿醒,而觀察者模式中场航,目標(biāo)和觀察者是直接聯(lián)系起來(lái)的。具體選擇什么模式廉羔,得視場(chǎng)景而定溉痢。一般來(lái)說(shuō),發(fā)布/訂閱就夠用了憋他,簡(jiǎn)單清晰孩饼,符合我們dom事件編程的觀念。
觀察者模式哪里被用到過(guò)竹挡?vue的雙向綁定镀娶。下篇就講一下觀察者模式在vue雙向綁定實(shí)現(xiàn)中的運(yùn)用。