釋出訂閱模式學習

Panthon發表於2018-04-10

生活中的釋出訂閱模式

小潘、小黃、小李都想要買部奧迪A4,一起去本市唯一一家4S店卻被告知沒有現車。4S店說:"如果您幾位不著急的話,我們可以從上海給調車,這可能需要等上個幾天(具體時間也不知道),幾位方便的話留個聯絡方式,一到車我會第一時間通知各位"。於是這3人在登記表上了留下了聯絡方式一些配置要求...在一個禮拜過後,車到了,4S店根據登記表一一聯絡了小潘、小黃、小李前來取車。

釋出訂閱的作用

上面的例子中,這3位留下聯絡方式,4S店一一通知他們(一對多的關係)前來取車就是一個典型的釋出訂閱模式。小潘,小黃,小李都是訂閱者,他們訂閱了車子到店的資訊,4S店作為釋出者,會在車子到店釋出資訊給訂閱者。

一步一步實現釋出訂閱

經過上面的例子,想必您對釋出訂閱模式或許有了些感官上的認識。如果還是覺得很模糊的話,那就跟著我一步一步來實現一個釋出訂閱。

動手之前的準備:

  • 首先要指定釋出者(就像4S店)
  • 然後要給一個快取列表,用於存放回撥函式以便告知訂閱者(就類似 登記表)
  • 最後要釋出訊息的時候,釋出者會遍歷快取列表,依次觸發回撥函式(4S店打登記表上的電話,通知他們前來取車)。
  1. 第一段程式碼

 function Sale(){//指定釋出者  定義一個4S店類
        this._typeList = {};//定義快取列表  存放回撥函式
    };
複製程式碼
為什麼把快取列表定義成物件{}?
答:就像現實中的買車,不同的消費者會需要不同品牌的汽車,{'奧迪','大眾','別克',....},4S店也經常
會遇到沒有現車的情況,所以就需要登記不同品牌的需求。並且,許多購車人都想知道訂購車的一些配置,
比如小潘訂閱了一部奧迪,他在登記表中新增了一些他關心的配置(比如:動力,油耗,空間...)這些配置就
類似回撥函式----奧迪:[動力,油耗,空間];等車子一到,4S店也會將相關配置告知小潘。複製程式碼

2.第二段程式碼

  Sale.prototype.on = function(type,fn){//指定並增加訂閱者
        if(!this._typeList[type]){//如果還沒有訂閱過此訊息,就給他建立一個快取列表   就像小潘
他們剛走,4S店來了一個人要邁巴赫,店裡也沒有現車,於是又在登記表上登記了
            this._typeList[type] = [];
        }
        this._typeList[type].push(fn);
    };複製程式碼

3.第三段程式碼

  Sale.prototype.emit = function(type,...arg){ //釋出訊息 車子一到店 就通知人取車
        if(this._typeList[type]){//如果之前有過此訂閱型別
            this._typeList[type].forEach(item=>item(...arg))//執行回撥 
        }else {//如果沒有訂閱  直接返回
            return false
        }
    };複製程式碼

4.前三段程式碼合併

function Sale(){
        this._typeList = {};
    };
    Sale.prototype.on = function(type,fn){
        if(!this._typeList[type]){
            this._typeList[type] = [];
        }
        this._typeList[type].push(fn);
    };
    Sale.prototype.emit = function(type,...arg){
        if(this._typeList[type]){
            this._typeList[type].forEach(item=>item(...arg))
        }else {
            return false
        }
    };

    var _4S = new Sale();
    function fuel(who) { //小潘需要4s店在A4到車後,告知油耗
        console.log('尊敬的'+who +'油耗=6.2-7.8L/100km');
    }
   function power(who) {//小潘需要4s店在A4到車後,告知其這車子的動力

       console.log('尊敬的'+who+'發動機=2.0T');
   }
    _4S.on('A4',fuel)//購車者XXX向4S店訂閱了 A4的訊息
    _4S.on('A4',power)
    _4S.emit('A4','小潘')//4S店向小潘釋出A4的訊息複製程式碼

突然不想要A4了

有時候,我們也許突然之間,不想再獲得我們訂閱的訊息,這時候就需要設定取消訂閱的功能。 小潘不想要A4了...

Sale.prototype.remove = function(type,fn){
    var len = this._typeList[type];
    if(!len){//如果這款品牌的車的沒人訂閱過  直接返回
        return false
    }
    if(!fn){//如果小潘沒有指定 4S店在A4到店後,要把哪些配置發給他(也即沒有傳入具體的回撥函式),則表示取消type對應的所有訂閱
        len = null;
    }else{
        for(var i = len.length-1;i>=0;i--){
            var _fn = len[i];
            if(_fn === fn){
                len.splice(i,1);//刪除訂閱的回撥函式
            }
        }
    }
}複製程式碼

全部的程式碼

function Sale(){
        this._typeList = {};
    };
    Sale.prototype.on = function(type,fn){
        if(!this._typeList[type]){
            this._typeList[type] = [];
        }
        this._typeList[type].push(fn);
    };
    Sale.prototype.emit = function(type,...arg){
        if(this._typeList[type]){
            this._typeList[type].forEach(item=>item(...arg))
        }else {
            return false
        }
    };
    Sale.prototype.remove = function(type,fn){    var len = this._typeList[type];
    if(!len){//如果這款品牌的車的沒人訂閱過  直接返回
        return false
    }
    if(!fn){//如果小潘沒有指定 4S店在A4到店後,要把哪些配置發給他(也即沒有傳入具體的回撥函式),
則表示取消type對應的所有訂閱
        len.length = 0

    }else{
        for(var i = len.length-1;i>=0;i--){
            var _fn = len[i];
            if(_fn === fn){
                len.splice(i,1);//刪除訂閱的回撥函式
            }
        }
    }
}
    var _4S = new Sale();
    function fuel(who) { //小潘需要4s店在A4到車後,告知油耗
        console.log('尊敬的'+who +'油耗=6.2-7.8L/100km');
    }
   function power(who) {//小潘需要4s店在A4到車後,告知其這車子的動力

       console.log('尊敬的'+who+'發動機=2.0T');
   }
    _4S.on('A4',fuel)//購車者XXX向4S店訂閱了 A4的訊息
    _4S.on('A4',power)
    _4S.on('A5',power)console.log(_4S._typeList);     _4S.remove('A4',fuel)
    _4S.emit('A4','小潘')//4S店向小潘釋出A4的訊息複製程式碼



相關文章