中介者模式

中介者模式是一种为了减少对象之间的耦合关系而存在的模式。当你的程序越来越大,每个对象所依赖的对象也越来越多,对象之间逐渐会形成网状的引用关系。逐渐的,你开始对每个对象的改动都变得小心翼翼,生怕一不小心,你就影响到了其他的对象。

中介者模式主要适用于有多个可能变化的对象,并且这些对象的变化会影响到其他一个或多个对象的场景。比如我们常见的网游组队系统,每个成员加入或离开队伍,都会对队伍的其他成员造成影响——这是多对多的场景。在常见的HTML5小游戏,比如换装小游戏中,你选择的每一件衣服都会对最终的效果产生影响——这是多对一的使用场景。

在中介者模式中,我们创造一个中介者,让中介者来管理对象之间的关系,无论那个对象发生变化,都将自身传给中介者,由中介者去处理后续的事情。

项目需求

我们此次项目目标是制作一个简易的在线海报生成系统,这个系统的目标用户是普通人而非专业设计师,所以我们要提供多个模版供用户选择。当然,这个项目毕竟是一个demo,所以我们不会做的太复杂。

我们需要为用户提供多个可供选择的背景,在背景正中央为海报的主题,主题可以重写,主题的字体也可以选择。最终效果如下:

需求分析

我们知道,本项目主要有三个变化的对象,他们都会影响到最终的效果。按照一般的思路,我们可以为每个选择框和输入框绑定事件,在他们发生变化的时候分别执行不同的操作。

项目骨架

由于我们demo的核心部分是Javascript。所以此处给出html和css部分。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo6</title>
    <style>
        .container{
            width: 600px;
            height: 500px;
            margin:0 auto;
        }
        .left,.right{
            box-sizing: border-box;
            width: 300px;
            float: left;
            height: 500px;
            border: 1px solid #000;
        }
        .box{
            margin-top: 100px;
            width: 300px;
            height: 300px;
            background-image: url(7-0.png);
            background-size: cover;
            overflow: hidden;
        }
        .box .word{
            font-size: 60px;
            color: #fff;
            margin-top: 120px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="left">
            <select name="background" id="background">
                <option value="0">背景1</option>
                <option value="1">背景2</option>
                <option value="2">背景3</option>
            </select>
            <br>
            <input type="text" name="cnt" placeholder="中心文字" id="input">
            <br>
            <select name="font" id="font">
                <option value="0">字体1</option>
                <option value="1">字体2</option>
                <option value="2">字体3</option>
            </select>
        </div>
        <div class="right">
            <div class="box">
                <div class="word">中心文字</div>
            </div>
        </div>
    </div>
</body>
</html>

核心代码

选中相关的元素

var back = document.getElementById("background");
var input = document.getElementById("input");
var font = document.getElementById("font");

当它们发生改变时,通知中介者,而非直接操作相关页面

// 当它们发生改变时,通知中介者
back.addEventListener("change",function(){
    mediator(this);
})
input.addEventListener("change",function(){
    mediator(this);
})
font.addEventListener("change",function(){
    mediator(this);
})

定义中介者,中介者会负责全部逻辑处理

//定义中介者
var mediator = function(ele){
    //选中要改变的元素
    var box = document.querySelector(".box");
    var word = document.querySelector(".word");
    //更改背景
    if(ele.name == "background"){
        console.log(box)
        box.style.backgroundImage = "url(7-"+ele.value+".png)";
    }
    //更改文字内容
    else if(ele.name == "cnt"){
        word.innerHTML = ele.value;
    }
    //更改字体
    else if(ele.name == "font"){
        var fontList = ["'Times New Roman', Times, serif","Georgia, serif","Courier New"]
        word.style.fontFamily = fontList[ele.value]
    }
}

总结

想象本demo如果不采用中介者,那么应该是这样实现的:为每个按钮绑定事件、当按钮状态改变时选中对应的元素、对元素执行相应的操作,这种思路同样可以实现功能,但是高耦合度的程序并没有很好的可扩展性,想象一下,如果某一天我们的需求更改为:改动某个选项,既可以改动主标题字体、又能改动副标题字体。或者既能更改背景,又能改动标题位置。想必你会深陷在各个对象方法中不能自拔,最终无奈的选择重构你的代码。

而中介者模式的存在,可以大大降低程序的耦合度,这种减少某个对象对其他对象的影响方式的行为叫做解耦。

但是中介者模式也存在一些缺点,有时,他虽然让你免于在相互关联的对象中寻找某一句关键的代码。但是中介者本身会变得难以维护,因此中介者内部的代码编写一定要条理清晰。另外,中介者本身也会占用内存资源,因此,往往在对象很多而且对象的相互联系会随着对象的数量呈爆炸式增长的场景,我们才会用到中介者。所以,我们要寻找到这个平衡。