1. 程式人生 > >js設計模式-發布/訂閱模式

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

創建 主題 sub str 狀態 cli handler n) 機制

一、前言

  發布訂閱模式,基於一個主題/事件通道,希望接收通知的對象(稱為subscriber)通過自定義事件訂閱主題,被激活事件的對象(稱為publisher)通過發布主題事件的方式被通知。

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

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

二、和觀察者模式的區別

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

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

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

(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("消息"); })()

2、可以看到觀察者模式有如下優點

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

這是一個完整的實現

(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

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