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
每一步都是一个深刻的脚印