有這么一段代碼經常會出現在代碼中
1 var pubsub = (()=>{ 2 var topics = {}; 3 function subscribe(topic,fn){ 4 if(!topics[topic]){ 5 topics[topic] = []; 6 } 7 topics[topic].push(fn); 8 } 9 function publish(topic,...args){ 10 if(!topics[topic]) 11 return; 12 for(let fn of topics[topic]){ 13 fn(...args); 14 } 15 } 16 return { 17 subscribe, 18 publish 19 } 20 })()
測試代碼
1 pubsub.subscribe('test',function(a,b){ //訂閱者A訂閱了test事件 2 console.log(a,b); 3 }); 4 pubsub.publish('test','123','HH'); //123 HH(發布者B發布了test事件)
有的時候我會叫他觀察者模式,有時候又會叫他發布訂閱模式,覺得叫什么都是對的。
但是,他們並不一樣。
差異
在觀察者模式中,觀察者需要直接訂閱目標事件。在目標發出內容改變的事件后,直接接收事件並作出響應。發布訂閱模式相比觀察者模式多了個事件通道,訂閱者和發布者不是直接關聯的。
這段話可以看出上面的例子是發布訂閱模式。訂閱者A和發布者B是通過pubsub這個對象關聯起來的,他們沒有直接的交流。
那么真正的觀察者模式是怎么樣的?
一個或多個觀察者對目標的狀態感興趣,通過將自己依附在目標對象上以便注冊所感興趣的內容。目標狀態發生改變並且觀察者可能對這些改變感興趣,會發送一個通知消息,調用每個觀察者的更新方法。當觀察者不再對目標狀態感興趣時,他們可以簡單將自己從中分離。
我們來實現下觀察者模式。首先是目標的構造函數,他有個數組,用於添加觀察者。還有個廣播方法,遍歷觀察者數組后調用他們的update方法:
1 class Subject{ 2 constructor(){ 3 this.subs = []; 4 } 5 addSub(sub){ 6 this.subs.push(sub); 7 } 8 notify(){ 9 this.subs.forEach(sub=> { 10 sub.update(); 11 }); 12 } 13 }
那么觀察者就得有個update方法:
1 class Observer{ 2 update(){ 3 console.log('update'); 4 } 5 }
測試代碼
1 let subject = new Subject(); 2 let ob = new Observer(); 3 //目標添加觀察者了 4 subject.addSub(ob); 5 //目標發布消息調用觀察者的更新方法了 6 subject.notify(); //update
可以看到目標和觀察者是直接聯系在一起的。觀察者把自身添加到了目標對象中,可見和發布訂閱模式差別還是很大的。在這種模式下,目標更像一個發布者,他讓添加進來的所有觀察者都執行了update函數,而觀察者就像一個訂閱者。
優劣
個人覺得發布/訂閱模式比較簡單,使用的也比較廣泛。由於他訂閱者和發布者不直接關聯的特點我們完全可以把管理事件的對象寫到一個單獨文件中,作為庫來使用。發布訂閱模式中,雙方不知道對方的存在,而觀察者模式中,目標和觀察者是直接聯系起來的。具體選擇什么模式,得視場景而定。一般來說,發布/訂閱就夠用了,簡單清晰,符合我們dom事件編程的觀念。
觀察者模式哪里被用到過?vue的雙向綁定。下篇就講一下觀察者模式在vue雙向綁定實現中的運用。
鏈接:https://www.jianshu.com/p/f0f22398d25d
來源:簡書