js设计模式——发布订阅模式
概念
发布订阅模式又叫观察者模式,它定义对象间一对多的依赖关系,当一个对象状态发生改变时,所有依赖于它的对象都将得到通知。
案例
在js设计模式与开发实践一书中使用的是楼盘信息更新发布的案例。大概内容是:想要买房的人们会订阅自己想要的房产信息,如果房产信息有更新,就会发布给这些人。
比如佩奇想买一个房子,他可以在售楼处(salesOffices
)去订阅这类房产消息,售楼处会将佩奇订阅的信息填写(listen
)在客户订阅表中(clientList
),当有房子出来时,售楼处就会发送(trigger
)信息给佩奇。
主要内容就是:
salesOffices={ clientList:[], listen:function, trigger:function }
代码如下:
<!DOCTYPE html> <html> <head> <title>发布订阅</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> </body> <script type="text/javascript"> var consoleText=function (text) { // body... let body=document.body; let div=document.createElement('div'); div.innerHTML=text; body.appendChild(div); } //简单发布-订阅模式 var salesOffices={}; salesOffices.clientList=[]; salesOffices.listen=function(fn){ this.clientList.push(fn); } salesOffices.trigger=function(){ for(var i=0,l=this.clientList.length;i<l;i++){ this.clientList[i].apply(this,arguments); } } salesOffices.listen(function(price,s){ consoleText('佩奇您好,现在有新楼盘:价格:'+price+",面积:"+s); }) salesOffices.listen(function(price,s){ consoleText('小红您好,现在有新楼盘:价格:'+price+",面积:"+s); }) salesOffices.trigger(6000000,120); </script> </html>
如果现在佩奇发现房价太高了,自己的预算只能付得起80平房子的首付,售楼处再给佩奇发120平的房子只会扎佩奇的心,所以佩奇只想订阅80平的房子的消息。
这时候只需要将订阅表分为不同的类型,想要哪种房子的消息就去哪张表填写信息,现在佩奇的信息只能出现在80平的表上了。
当有80平的信息出来时,只需给将80平订阅表的用户发送消息即可
salesOffices={ clientList:{ square80:[], square120:[], }, listen:function, trigger:function }
代码如下:
<!DOCTYPE html> <html> <head> <title>发布订阅</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> </body> <script type="text/javascript"> var consoleText=function (text) { // body... let body=document.body; let div=document.createElement('div'); div.innerHTML=text; body.appendChild(div); } //可选类型发布-订阅模式 var salesOffices={}; salesOffices.clientList={}; salesOffices.listen=function(key,fn){ //将key类型的订阅存储起来 if(!this.clientList[key]){ this.clientList[key]=[] } this.clientList[key].push(fn); } salesOffices.trigger=function(){ let key=Array.prototype.shift.call(arguments); fns=this.clientList[key]; if(!fns||fns.length===0){ return false; } for(var i=0,l=fns.length;i<l;i++){ fns[i].apply(this,arguments); } } salesOffices.listen("square80",function(price){ consoleText('小明您好,现在有新楼盘80平:价格:'+price); }) salesOffices.listen("square80",function(price){ consoleText('小李您好,现在有新楼盘80平:价格:'+price); }) salesOffices.listen("square110",function(price){ consoleText('小红您好,现在有新楼盘110平:价格:'+price); }) salesOffices.trigger("square80",12000000); </script> </html>
佩奇之后找到了心仪的房子,已经不需要售楼处再发消息了,所以还有取消订阅的功能。
而这种发布订阅的模式很有用,很多行业都可以使用它,所以如果能安装即用就会很nice
代码如下
<!DOCTYPE html> <html> <head> <title>发布订阅</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> </body> <script type="text/javascript"> var consoleText=function (text) { // body... let body=document.body; let div=document.createElement('div'); div.innerHTML=text; body.appendChild(div); } //通用发布订阅模式 var event={ clientList:{}, listen:function(key,fn){ if(!this.clientList[key]) this.clientList[key]=[]; this.clientList[key].push(fn); }, trigger:function(){ var key=Array.prototype.shift.call(arguments); var fns=this.clientList[key]; if(!fns||fns.length===0) return false; for(var i=0,l=fns.length;i<l;i++){ fns[i].apply(this,arguments); } }, remove:function(key,fn){ //取消订阅 var fns=this.clientList[key]; if(!fns){// 如果 key 对应的消息没有被人订阅,则直接返回 return false; } if(!fn){ // 如果没有传入具体的回调函数,表示需要取消 key 对应消息的所有订阅 fns&&(fns.length=0); }else{ for(var l=fns.length;l>=0;l--){ if(fns[l]===fn){ fns.splice(l,1); } } } } } var installEvent=function(obj){ for(let i in event){ obj[i]=event[i]; } } var salesOffices={}; installEvent(salesOffices); //key的选择,我觉得应该是某个变化的条件 salesOffices.listen("square80",f1=function(price){ consoleText('小明您好,现在有新楼盘80平:价格:'+price); }) salesOffices.listen("square80",f2=function(price){ consoleText('小李您好,现在有新楼盘80平:价格:'+price); }) salesOffices.listen("square110",f3=function(price){ consoleText('小红您好,现在有新楼盘110平:价格:'+price); }) salesOffices.remove("square80",f2); salesOffices.trigger("square80",80); </script> </html>