今天我们聊一下中介者模式。
中介者模式跟观察者模式非常像,不过有一点细微的差别:
观察者是订阅和发布两个动作都要做;而中介者是提前订阅好了,只负责发布。
以自定义事件为例,on是监听一个事件,emit是让这个事件发生,这是观察者模式;而中介者模式并不需要on,只需emit。
看一下代码实现:
let Mediator = (function(){
let callbacks = {}
return {
register:function(type,action){//订阅
if(callbacks[type]){
callbacks[type].push(action)
} else {
callbacks[type] = []
callbacks[type].push(action)
}
},
emit:function(type){//发布
if(callbacks[type]){
for(let i=0;i<callbacks[type].length;i++){
callbacks[type][i] && callbacks[type][i]()
}
}
}
}
})()
代码还是非常简单的,关键是如何使用?什么场景下使用?
比如在一个复杂的网页下有很多模块,如果要在这个页面加一个效果,你肯定不会写一个函数,然后一个一个模块去调用对吧?这样的工作量不仅巨大而且容易遗漏。
解决问题的思路在于解除模块之间的耦合,最好在不修改其他模块的基础上,添加上这个功能。
假设有这么一个需求:
在用户的订单页,加个设置的需求,用户可以选择——是否显示每项右上方的红色消息提示。
页面有三个模块:我的订单,我的钱包,互动签到,其中涉及到消息提示的是前两个。
先写一个显示隐藏的方法:
function showHide(mod,tagName,status){
//获取模块
let mod = document.getElementById(mod)
//获取模块下的标签
let tag = mod.getElementsByTagName(tagName)
for(let i=0;i<tag.length;i++){
tag[i].style.visibility = status
}
}
然后是选择显示隐藏的动作:
(function(){
let btn = document.getElementById('hide_btn')//开关按钮
btn.onchange = function(){
if(btn.checked){
showHide('orderMod','span','visible')
showHide('walletMod','span','visible')
} else {
showHide('orderMod','span','hidden')
showHide('walletMod','span','hidden')
}
}
})()
这不就实现了?不挺好的嘛,没用到什么中介者啊?
如果是这样设计,这个设置模块,跟订单和钱包两个模块又产生了耦合。
最好的方案是解除任何模块之间的耦合,这样更便于单元测试与维护。
这时中介者模式就派上了用场:
let Mediator = (function(){
let callbacks = {}
return {
register:function(type,action){//订阅
if(callbacks[type]){
callbacks[type].push(action)
} else {
callbacks[type] = []
callbacks[type].push(action)
}
},
emit:function(type){//发布
if(callbacks[type]){
for(let i=0;i<callbacks[type].length;i++){
callbacks[type][i] && callbacks[type][i]()
}
}
}
}
})()
//模块下的标签操作
function showHide(mod,tagName,status){
//获取模块
let mod = document.getElementById(mod)
//获取模块下的标签
let tag = mod.getElementsByTagName(tagName)
for(let i=0;i<tag.length;i++){
tag[i].style.visibility = status
}
}
//提前注册显示事件
Mediator.register('showMsg',function(){
showHide('orderMod','span','visible')
})
Mediator.register('showMsg',function(){
showHide('walletMod','span','visible')
})
//提前注册隐藏事件
Mediator.register('hideMsg',function(){
showHide('orderMod','span','hidden')
})
Mediator.register('hideMsg',function(){
showHide('walletMod','span','hidden')
})
//设置模块
(function(){
let btn = document.getElementById('hide_btn')//开关按钮
btn.onchange = function(){
if(btn.checked){
Mediator.emit('showMsg')
} else {
Mediator.emit('hideMsg')
}
}
})()
这样,设置模块跟其他的模块就彻底解耦了。
网友评论