js設計模式-發佈/訂閱模式

1、前言html

  發佈訂閱模式,基於一個主題/事件通道,但願接收通知的對象(稱爲subscriber)經過自定義事件訂閱主題,被激活事件的對象(稱爲publisher)經過發佈主題事件的方式被通知。數組

  就和用戶訂閱微信公衆號道理同樣,一個公衆號能夠被多個用戶同時訂閱,當公衆號有新增內容時候,只要發佈就行了,用戶就能接收到最新的內容。微信

  js中的事件監聽機制就是一種觀察者模式。app

2、和觀察者模式的區別函數

  觀察者模式:一個對象(稱爲subject)維持一系列依賴於它的對象(稱爲observer),將有關狀態的任何變動自動通知給它們(觀察者)。this

  一、Observer模式要求觀察者必須訂閱內容改變的事件,定義了一個一對多的依賴關係;
       二、Publish/Subscribe模式使用了一個主題/事件通道,這個通道介於訂閱着與發佈者之間;
       三、觀察者模式裏面觀察者「被迫」執行內容改變事件(subject內容事件);發佈/訂閱模式中,訂閱着能夠自定義事件處理程序;
       四、觀察者模式兩個對象之間有很強的依賴關係;發佈/訂閱模式兩個對象之間的耦合讀底spa

這是一個簡單的實現,主要是建立一個對象,有三個屬性(容器,訂閱方法,發佈方法)。將訂閱者放入容器,發佈,觸發容器內的函數。prototype

(function(){

    //
    function Public(){
        //存放訂閱者的容器
        this.subscribers=[];
        //添加訂閱者
        this.addSubscribers=function(fn){
            let isExit = this.subscribers.some(function(sub){
                return fn == sub;
            })
            if(!isExit){
                this.subscribers.push(fn);
            }
            return this;
        }
    
    //發佈消息
    this.deliver = function(data){
        this.subscribers.forEach(function(fn){
            fn(data);
        })
        return this;
    }    
    }
    
    let a = function(data){
        console.log("a:"+data);
    }
    let b = function(data){
        console.log("b:"+data);
    }

    let c = function(data){
        console.log("c:"+data);
    }

    var pub = new Public();
    pub.addSubscribers(a).addSubscribers(b).addSubscribers(c);
    pub.deliver("消息");
})()

二、能夠看到觀察者模式有以下優勢code

  a、每個訂閱者都是相互獨立的只和發佈者有關係,與發佈者是一對多的關係,也能夠是一對一的關係。
  b、每個訂閱者能夠根據本身的需求來調用,而不影響其它訂閱者
  c、與第一種方式相比,第二種方式的代碼可讀性、可維護性強;server

這是一個完整的實現

(function(win){
    function Public(){
        this.handlers={};    
    }
    Public.prototype = {
        //訂閱事件
        on:function(eventType,eventHandle){
            var self = this;
            if(!(eventType in self.handlers)){
                self.handlers[eventType] = [];
            }
            self.handlers[eventType].push(eventHandle);
            return this;
        },
        emit:function(eventType){
            //若是調用函數傳了多個參數,eventType指第一個參數,arguments是一個對象,參數序號是key指,同時也給他length
            //看起來像數組,其實不是數組。
            var self = this;
            //去除第一個事件類型的參數,使用call改變this指向
            //使用slice的對象須要由length屬性,因此arguments才能使用成功。
            var handleArgs = Array.prototype.slice.call(arguments,1);
            console.log(handleArgs);
            for (var i =0; i<self.handlers[eventType].length;i++) {
                //使用apply,訂閱者的調用對象就是Public,不適用就是數組對象。
                self.handlers[eventType][i].apply(self,handleArgs);
            }
            return this;
        },
        off:function(eventType,eventHandle){
            var currentEvent = this.handlers[eventType];
            var len = 0;
            if(currentEvent){
                len = currentEvent.length;
if(eventHandle == undefined){ currentEvent[eventType] = []; }else{ for (var i = len-1;i >= 0;i--) { if(currentEvent[i] == eventHandle){ currentEvent.splice(i,1); } } } } } } var a = function(data){ console.log(this); console.log("a"+data); } var b =function(data){ console.log("b"+data); }    var pub = new Public(); pub.on("click",a).on("click",b); pub.emit("click","xiaoxi"); })(window)

參考博主的文章:https://www.cnblogs.com/leaf930814/p/9014200.html

相關文章
相關標籤/搜索