中介者模式

作者: 姜治宇 | 来源:发表于2020-04-03 21:54 被阅读0次

    今天我们聊一下中介者模式。
    中介者模式跟观察者模式非常像,不过有一点细微的差别:
    观察者是订阅和发布两个动作都要做;而中介者是提前订阅好了,只负责发布。
    以自定义事件为例,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]()
                    }
                }
            }
        }
    })()
    

    代码还是非常简单的,关键是如何使用?什么场景下使用?
    比如在一个复杂的网页下有很多模块,如果要在这个页面加一个效果,你肯定不会写一个函数,然后一个一个模块去调用对吧?这样的工作量不仅巨大而且容易遗漏。
    解决问题的思路在于解除模块之间的耦合,最好在不修改其他模块的基础上,添加上这个功能。
    假设有这么一个需求:
    在用户的订单页,加个设置的需求,用户可以选择——是否显示每项右上方的红色消息提示。

    mt.jpeg
    页面有三个模块:我的订单,我的钱包,互动签到,其中涉及到消息提示的是前两个。
    先写一个显示隐藏的方法:
    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')
            }
        }
    
    })()
    

    这样,设置模块跟其他的模块就彻底解耦了。

    相关文章

      网友评论

        本文标题:中介者模式

        本文链接:https://www.haomeiwen.com/subject/wyvkphtx.html