談談觀察者模式和釋出訂閱模式

淘淘笙悅發表於2018-10-01

在網上看到許多關於觀察者模式和釋出訂閱模式的博文,發現很多人都認為觀察者模式即釋出訂閱模式,經過進一步的學習和理解,我認為觀察者模式和釋出訂閱模式還是有一些區別的,下面談談我對觀察者模式和釋出訂閱模式的理解「PS:歡迎各路大神指正」。

觀察者模式(Observer)

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

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

在 Subject 物件新增了一系列 Observer 物件之後,Subject 物件則維持著這一系列 Observer 物件,當有關狀態發生變更時 Subject 物件則會通知這一系列 Observer 物件進行更新。

function Subject(){
  this.observers = [];
}

Subject.prototype = {
  add:function(observer){  // 新增
    this.observers.push(observer);
  },
  remove:function(observer){  // 刪除
    var observers = this.observers;
    for(var i = 0;i < observers.length;i++){
      if(observers[i] === observer){
        observers.splice(i,1);
      }
    }
  },
  notify:function(){  // 通知
    var observers = this.observers;
    for(var i = 0;i < observers.length;i++){
      observers[i].update();
    }
  }
}

function Observer(name){
  this.name = name;
}

Observer.prototype = {
  update:function(){  // 更新
    console.log('my name is '+this.name);
  }
}

var sub = new Subject();

var obs1 = new Observer('ttsy1');
var obs2 = new Observer('ttsy2');

sub.add(obs1);
sub.add(obs2);
sub.notify();  //my name is ttsy1、my name is ttsy2
複製程式碼

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

在 Subject 物件新增了一系列 Observer 物件之後,還可以通過 remove 方法移除某個 Observer 物件對它的依賴。

var sub = new Subject();

var obs1 = new Observer('ttsy1');
var obs2 = new Observer('ttsy2');

sub.add(obs1);
sub.add(obs2);
sub.remove(obs2);
sub.notify();  //my name is ttsy1
複製程式碼

釋出訂閱模式(Publisher && Subscriber)

釋出訂閱模式指的是希望接收通知的物件(Subscriber)基於一個主題通過自定義事件訂閱主題,被啟用事件的物件(Publisher)通過釋出主題事件的方式通知各個訂閱該主題的 Subscriber 物件。

let pubSub = {
  list:{},
  subscribe:function(key,fn){  // 訂閱
    if (!this.list[key]) {
      this.list[key] = [];
    }
    this.list[key].push(fn);
  },
  publish:function(){  // 釋出
    let arg = arguments;
    let key = [].shift.call(arg);
    let fns = this.list[key];

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

    for(var i=0,len=fns.length;i<len;i++){
      fns[i].apply(this, arg);
    }

  },
  unSubscribe(key) {  // 取消訂閱
    delete this.list[key];
  }
};

pubSub.subscribe('name', (name) => {
  console.log('your name is ' + name);
});
pubSub.subscribe('sex', (sex) => {
  console.log('your sex is ' + sex);
});
pubSub.publish('name', 'ttsy1');  // your name is ttsy1
pubSub.publish('sex', 'male');  // your sex is male
複製程式碼

上述程式碼的訂閱是基於 name 和 sex 主題來自定義事件,釋出是通過 name 和 sex 主題並傳入自定義事件的引數,最終觸發了特定主題的自定義事件。

可以通過 unSubscribe 方法取消特定主題的訂閱。

pubSub.subscribe('name', (name) => {
  console.log('your name is ' + name);
});
pubSub.subscribe('sex', (sex) => {
  console.log('your sex is ' + sex);
});
pubSub.unSubscribe('name');
pubSub.publish('name', 'ttsy1');  // 這個主題被取消訂閱了
pubSub.publish('sex', 'male');  // your sex is male
複製程式碼

觀察者模式 VS 釋出訂閱模式

觀察者模式與釋出訂閱模式

觀察者模式與釋出訂閱模式都是定義了一個一對多的依賴關係,當有關狀態發生變更時則執行相應的更新。

不同的是,在觀察者模式中依賴於 Subject 物件的一系列 Observer 物件在被通知之後只能執行同一個特定的更新方法,而在釋出訂閱模式中則可以基於不同的主題去執行不同的自定義事件。相對而言,釋出訂閱模式比觀察者模式要更加靈活多變。

我認為,觀察者模式和釋出訂閱模式本質上的思想是一樣的,而釋出訂閱模式可以被看作是觀察者模式的一個進階版。

設計模式只是一種思想,某一種設計模式都可以有很多種不同的實現方式,各種實現都有其優劣之分,具體的實現方式需要基於不同的業務場景。上述是我對觀察者模式和釋出訂閱模式學習之後的一些理解,望指正。

不定時分享個人在前端方面的學習經驗,覺得還不錯的小夥伴,可以關注一波公眾號哦。

談談觀察者模式和釋出訂閱模式

相關文章