重學(xué)JS(九)—— 觀察者模式和發(fā)布/訂閱模式真不一樣

有這么一段代碼經(jīng)常會出現(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
  }
})()

測試代碼

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ù)全部執(zhí)行一遍而已。但是對于一個沒讀過實現(xiàn)代碼的人來說,卻是一個神奇的存在,JS居然能訂閱發(fā)布消息,太酷了。
有的時候我會叫他觀察者模式,有時候又會叫他發(fā)布訂閱模式,覺得叫什么都是對的。
但是,他們并不一樣。

差異

在觀察者模式中,觀察者需要直接訂閱目標(biāo)事件。在目標(biāo)發(fā)出內(nèi)容改變的事件后,直接接收事件并作出響應(yīng)。發(fā)布訂閱模式相比觀察者模式多了個事件通道,訂閱者和發(fā)布者不是直接關(guān)聯(lián)的。
這段話可以看出上面的例子是發(fā)布訂閱模式。訂閱者A和發(fā)布者B是通過pubsub這個對象關(guān)聯(lián)起來的,他們沒有直接的交流。

那么真正的觀察者模式是怎么樣的?

一個或多個觀察者對目標(biāo)的狀態(tài)感興趣,通過將自己依附在目標(biāo)對象上以便注冊所感興趣的內(nèi)容。目標(biāo)狀態(tài)發(fā)生改變并且觀察者可能對這些改變感興趣,會發(fā)送一個通知消息,調(diào)用每個觀察者的更新方法。當(dāng)觀察者不再對目標(biāo)狀態(tài)感興趣時,他們可以簡單將自己從中分離。

我們來實現(xiàn)下觀察者模式。首先是目標(biāo)的構(gòu)造函數(shù),他有個數(shù)組,用于添加觀察者。還有個廣播方法,遍歷觀察者數(shù)組后調(diào)用他們的update方法:

class Subject{
  constructor(){
    this.subs = [];
  }
  addSub(sub){
    this.subs.push(sub);
  }
  notify(){
    this.subs.forEach(sub=> {
      sub.update();
    });
  }
}

那么觀察者就得有個update方法:

class Observer{
  update(){
    console.log('update');
  }
}

測試代碼

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)對象中,可見和發(fā)布訂閱模式差別還是很大的。在這種模式下,目標(biāo)更像一個發(fā)布者,他讓添加進來的所有觀察者都執(zhí)行了update函數(shù),而觀察者就像一個訂閱者。

優(yōu)劣

個人覺得發(fā)布/訂閱模式比較簡單,使用的也比較廣泛。由于他訂閱者和發(fā)布者不直接關(guān)聯(lián)的特點我們完全可以把管理事件的對象寫到一個單獨文件中,作為庫來使用。發(fā)布訂閱模式中,雙方不知道對方的存在,而觀察者模式中,目標(biāo)和觀察者是直接聯(lián)系起來的。具體選擇什么模式,得視場景而定。一般來說,發(fā)布/訂閱就夠用了,簡單清晰,符合我們dom事件編程的觀念。
觀察者模式哪里被用到過?vue的雙向綁定。下篇就講一下觀察者模式在vue雙向綁定實現(xiàn)中的運用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1 場景問題# 1.1 訂閱報紙的過程## 來考慮實際生活中訂閱報紙的過程,這里簡單總結(jié)了一下,訂閱報紙的基本流程...
    七寸知架構(gòu)閱讀 4,648評論 5 57
  • 工廠模式類似于現(xiàn)實生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實現(xiàn)同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,808評論 2 17
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,833評論 25 708
  • 靜靜的愛著這么一個人 從開始到時光的盡頭 并不想遇見最好的你 而渴望相逢在故事的最初 那時風(fēng)剛剛開始變暖 那時的我...
    臥龍飲水閱讀 352評論 0 2
  • 推送技術(shù)產(chǎn)生場景: --服務(wù)器端主動性: 客戶端與服務(wù)器交互都是客戶端主動的, 服務(wù)器一般不能主動與客戶端進行數(shù)據(jù)...
    原軍鋒閱讀 34,767評論 4 60