js設計模式之【觀察者模式】VS【發布/訂閱模式模式】的區別?


 兩種模式存在一定區別

一、觀察者模式(Observer)

      觀察者模式指的是一個對象(Subject)維持一系列依賴於它的對象(Observer),當有關狀態發生變更時 Subject 對象則通知一系列 Observer 對象進行更新。

      在觀察者模式中,Subject 對象擁有添加、刪除和通知一系列 Observer 的方法等等,而 Observer 對象擁有更新方法等等。

// 定義一個主體對象
class Subject {
  constructor() {
    this.Observers = [];
  }
  add(observer) { //添加
    this.Observers.push(observer)
  }
  remove(observer) {//移除
    this.Observers.filter(item => item === observer);
  }
  notify() {
    this.Observers.forEach(item => {
      item.update();
    })
  }
}
//定義觀察着對象
class Observer {
  constructor(name) {
    this.name = name;
  }
  update() {
    console.log(`my name is:${this.name}`);
  }
}

//測試
let sub = new Subject();
let obs1 = new Observer('leaf111');
let obs2 = new Observer('leaf222');
sub.add(obs1);
sub.add(obs2);
sub.notify();

    上述代碼中,我們創建了 Subject 對象和兩個 Observer 對象,當有關狀態發生變更時則通過 Subject 對象的 notify 方法通知這兩個 Observer 對象,這兩個 Observer 對象通過 update 方法進行更新。

 

二、發布訂閱模式(Publisher && Subscriber)

      發布訂閱模式指的是希望接收通知的對象(Subscriber)基於一個主題通過自定義事件訂閱主題,被激活事件的對象(Publisher)通過發布主題事件的方式通知各個訂閱該主題的 Subscriber 對象。

      

let pubSub = {
  subs: [],
  subscribe(key, fn) { //訂閱
    if (!this.subs[key]) {
      this.subs[key] = [];
    }
    this.subs[key].push(fn);
  },
  publish(...arg) {//發布
    let args = arg;
    let key = args.shift();
    let fns = this.subs[key];

    if (!fns || fns.length <= 0) return;

    for (let i = 0, len = fns.length; i < len; i++) {
      fns[i](args);
    }
  },
  unSubscribe(key) {
    delete this.subs[key]
  }
}

//測試
pubSub.subscribe('name', name => {
  console.log(`your name is ${name}`);
})
pubSub.subscribe('gender', gender => {
  console.log(`your name is ${gender}`);
})
pubSub.publish('name', 'leaf333');  // your name is leaf333
pubSub.publish('gender', '18');  // your gender is 18

 

三、區別 

 如上圖所示:

       1、在觀察者模式中,觀察者是知道Subject的,Subject一直保持對觀察者進行記錄。然而,在發布訂閱模式中,發布者和訂閱者不知道對方的存在。它們只有通過消息代理進行通信。

       2、在發布訂閱模式中,組件是松散耦合的,正好和觀察者模式相反。 

       3、觀察者模式大多數時候是同步的,比如當事件觸發,Subject就會去調用觀察者的方法。而發布-訂閱模式大多數時候是異步的(使用消息隊列)。
 

四、vue中的作用

      Vue會遍歷實例的data屬性,把每一個data都設置為訪問器,然后在該屬性的getter函數中將其設為watcher,在setter中向其他watcher發布改變的消息。

   //遍歷傳入實例的data對象的屬性,將其設置為Vue對象的訪問器屬性
    function observe(obj,vm){
        Object.keys(obj).forEach(function(key){
            defineReactive(vm,key,obj[key]);
        });
    }
    //設置為訪問器屬性,並在其getter和setter函數中,使用訂閱發布模式。互相監聽。
    function defineReactive(obj,key,val){
        //這里用到了觀察者模式,它定義了一種一對多的關系,讓多個觀察者監聽一個主題對象,這個主題對象的狀態發生改變時會通知所有觀察者對象,觀察者對象就可以更新自己的狀態。
        //實例化一個主題對象,對象中有空的觀察者列表
        var dep = new Dep();
        //將data的每一個屬性都設置為Vue對象的訪問器屬性,屬性名和data中相同
        //所以每次修改Vue.data的時候,都會調用下邊的get和set方法。然后會監聽v-model的input事件,當改變了input的值,就相應的改變Vue.data的數據,然后觸發這里的set方法
        Object.defineProperty(obj,key,{
            get: function(){
                //Dep.target指針指向watcher,增加訂閱者watcher到主體對象Dep
                if(Dep.target){
                    dep.addSub(Dep.target);
                }
                return val;
            },
            set: function(newVal){
                if(newVal === val){
                    return
                }
                val = newVal;
                //console.log(val);
                //給訂閱者列表中的watchers發出通知
                dep.notify();
            }
        });
    }

    //主題對象Dep構造函數
    function Dep(){
        this.subs = [];
    }
    //Dep有兩個方法,增加訂閱者  和  發布消息
    Dep.prototype = {
        addSub: function(sub){
            this.subs.push(sub);
        },
        notify: function(){
            this.subs.forEach(function(sub){
                sub.update();
            });
        }
    }

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM