• js设计模式-发布/订阅模式


    一、前言

      发布订阅模式,基于一个主题/事件通道,希望接收通知的对象(称为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

    每一步都是一个深刻的脚印
  • 相关阅读:
    至最近写的微博记录(一)
    对古人“一命二运三风水,四积德五读书”的人生命运总结的理解
    福建省获得央行颁发的非金融机构支付业务许可牌照的公司(至20120801)
    替信息系统运维工作正名
    在信息系统运维开发中,对MVC框架认识上的一种变通
    Elasticsearch 从入门到学会之六(索引API特殊管理)
    Python的Web项目实现 Flask
    python的方法整理
    Shell脚本
    各种测试场景case整理
  • 原文地址:https://www.cnblogs.com/chzlh/p/10050487.html
Copyright © 2020-2023  润新知