JS訂閱釋出模式

zifeiyu發表於2018-12-04

什麼是釋出訂閱模式

釋出-訂閱模式又叫做觀察者模式。他定義了一種一對多的依賴關係,即當一個物件的狀態發生變化的時候,所有依賴的物件都會得到通知。

基本實現

把自己想象成公司的祕書,領導需要開一個會議,需要你去通知所有參會人員;

這裡有幾個元素:

  • 釋出者(祕書)
  • 與會人員(需要參加會議的人員)

還有幾個方法:

  • 製作與會人員名單
  • 刪除不參加的人
  • 傳送會議通知,以及必要的時間地點等資訊

你首先需要把所有的與會人員名單收集起來(也就是新增依賴函式),然後根據清單傳送通知,並攜帶必要的會議資訊,與會人員收到資訊後會做出相應的反應(回撥函式中的處理邏輯)

let yourMsg = {};
yourMsg.peopleList = [];
yourMsg.listen = function (fn) {
    this.peopleList.push(fn);
}
yourMsg.triger = function () {
  let that = this
  let args = arguments
  setTimeout(function() {
    for(let i = 0,fn;fn=that.peopleList[i++];){
        fn.apply(that,args);
    }
  },2000)
    
}

yourMsg.listen(function () {
    console.log('我被通知了,我回去參加會議,給我時間地點')
    console.log(`title:${arguments[0]}`);
    console.log(`time:${arguments[1]}`);
})
yourMsg.listen(function () {
  console.log('我被通知了,但是我不care')
})
yourMsg.listen(function () {
  console.log('我被通知了,Jack代替我去')
})

yourMsg.triger('會議', '3:00');

複製程式碼

這便是一個簡單的訂閱釋出模式

分主題的訂閱釋出模式

隨著公司業務量的增加,你的會議不需要所有人都參加,你需要分主題維護一份參會人員名單;

比如,產品會議需要小A,小B參加;而技術會議需要小C,小D參加;

這裡我們通過在新增與會人員的時候新增一個‘key’值代表該成員需要參加的會議型別;

let yourMsg = {};
yourMsg.peopleList = [];
yourMsg.listen = function (key, fn) {
  if (!this.peopleList[key]) {
    this.peopleList[key] = [] // 如果分類中沒有此型別的訊息,則新建一個
  }
  this.peopleList[key].push(fn);
}
yourMsg.triger = function () {
  let key = Array.prototype.shift.call(arguments)
  let fns = this.peopleList[key]
  let that = this
  let args = arguments
  if (!fns) {
    return false
  }
  setTimeout(function() {
    for(let i = 0,fn;fn=fns[i++];){
        fn.apply(that,args);
    }
  }, 200)
    
}

yourMsg.listen('prod', function () {
    console.log('小A: 我只關心會議訊息,其它的事別來煩我')
    console.log(`title:${arguments[0]}`);
    console.log(`time:${arguments[1]}`);
})
yourMsg.listen('prod', function () {
    console.log('小B: 會議使我精神百倍!')
    console.log(`title:${arguments[0]}`);
    console.log(`time:${arguments[1]}`);
})
yourMsg.listen('tech', function () {
  console.log('小C:我只關心技術會議,產品會議讓那些傻瓜去吧')
})
yourMsg.listen('tech', function () {
  console.log('小D:又到技術會議時間了?我是被逼的!')
})

yourMsg.triger('prod', '開會啦', '下午3:00');
yourMsg.triger('tech');
複製程式碼

可以隨處呼叫的訂閱釋出功能

由於你們公司效益特別好,你一個祕書已經忙不過來,這個時候,公司又來了一位祕書。你只需要把你通知會議安排的方法告訴他,讓他按照這個模式去做就好了。

這裡我們並沒有用物件來做,而是通過Object.Create()通過依賴關係來實現類似繼承的效果;更加的合理簡潔;個人我認為在js中完全沒必要也不應該使用物件導向的模式,因為它壓根就麼有所謂的物件導向,相比於東施效顰不如發揮自己的特點。

let installer = {
  peopleList: [],
  listen (key, fn) {
    if (!this.peopleList[key]) {
      this.peopleList[key] = [] // 如果分類中沒有此型別的訊息,則新建一個
    }
    this.peopleList[key].push(fn);
  },
  triger () {
    let key = Array.prototype.shift.call(arguments)
    let fns = this.peopleList[key]
    let that = this
    let args = arguments
    if (!fns) {
      return false
    }
    setTimeout(function() {
      for(let i = 0,fn;fn=fns[i++];){
          fn.apply(that,args);
      }
    }, 200)
      
  },
  remove (key, fn) {
    let fns = this.peopleList[key]
    if (!fns) {
      return false
    }

    for (let index = 0; index < fns.length; index++) {
      const _fn = fns[index];
      if(_fn === fn){
          fns.splice(index,1);
      }
    }
  }
}

let yourMsg = Object.create(installer);

yourMsg.listen('prod', function () {
    console.log('小A: 我只關心會議訊息,其它的事別來煩我')
    console.log(`title:${arguments[0]}`);
    console.log(`time:${arguments[1]}`);
})
yourMsg.listen('prod', function () {
    console.log('小B: 會議使我精神百倍!')
    console.log(`title:${arguments[0]}`);
    console.log(`time:${arguments[1]}`);
})


let smA = function () {
  console.log('小C:我只關心技術會議,產品開會讓那些傻瓜去吧')
}
let smB = function () {
  console.log('小D:又到技術會議時間了?我是被逼的!')
}
yourMsg.listen('tech', smA)
yourMsg.listen('tech', smB)

yourMsg.remove('tech', smA)

yourMsg.triger('prod', '開會啦', '下午3:00');
yourMsg.triger('tech', smA);
複製程式碼

相關文章