前言

中介者模式(Mediator Pattern)是一种行为设计模式,其主要目的是降低多个对象间的通信复杂性。这种模式提供了一个中介者对象,这个对象通常封装有具体对象之间交互的方式,使得对象之间不需要显式地相互引用,从而使其耦合松散,可以独立地改变它们之间的交互。

中介者模式就是为了解耦多个对象之间的关联,让他们不在相互依赖,而是依赖一个公共的对象,这个对象就是中介者。

中介者模式优化后:

中介者模式例子:购买商品

我们有一个手机购买页面,手机目前配置选项有:颜色,我们需要根据用户选择的颜色和购买数量,来控制购买按钮是否可以点击,已经库存是否足够。

<body>
    选择颜色: <select id="colorSelect"> 
               <option value="">请选择</option> 
               <option value="red">红色</option> 
               <option value="blue">蓝色</option> 
            </select> 
 
 输入购买数量: <input type="text" id="numberInput" /> 
 
 您选择了颜色:<div id="colorInfo"></div><br/> 
 您输入了数量: <div id="numberInfo"></div><br/>
 
    <button id="nextBtn" disabled="true">请选择手机颜色和购买数量</button>
</body>

我们有一个下拉选项用于选择颜色,一个输入框用于用户输入购买的数量,一个nextBtn购买按钮。

   var colorSelect = document.getElementById('colorSelect'),
       numberInput = document.getElementById('numberInput'),
       colorInfo = document.getElementById('colorInfo'),
       numberInfo = document.getElementById('numberInfo'),
       nextBtn = document.getElementById('nextBtn');

   var goods = { // 手机库存
       "red": 3,
       "blue": 6
   };
   colorSelect.onchange = function() {
       var color = this.value, // 颜色
           number = numberInput.value, // 数量
           stock = goods[color]; // 该颜色手机对应的当前库存
       colorInfo.innerHTML = color;
       
       if (!color) {
           nextBtn.disabled = true;
           nextBtn.innerHTML = '请选择手机颜色';
           return;
       }
       
       if (((number - 0) | 0) !== number - 0) { // 用户输入的购买数量是否为正整数
           nextBtn.disabled = true;
           nextBtn.innerHTML = '请输入正确的购买数量';
           return;
       }
       
       if (number > stock) { // 当前选择数量没有超过库存量
           nextBtn.disabled = true;
           nextBtn.innerHTML = '库存不足';
           return;
       }
       
       nextBtn.disabled = false;
       nextBtn.innerHTML = '放入购物车';
   };

可以看到下拉选项的change事件中,我们需要获取颜色并设置,还需要获取用户输入的购买数量,然后再去仓库里进行判断是否可以购买。

如果我们再新增一个配置项,就是手机的存储。

<body>
    选择颜色: <select id="colorSelect"> 
               <option value="">请选择</option> 
               <option value="red">红色</option> 
               <option value="blue">蓝色</option> 
            </select>

    选择内存: <select id="memorySelect"> 
               <option value="">请选择</option> 
               <option value="32G">32G</option> 
               <option value="16G">16G</option> 
             </select>
 
 输入购买数量: <input type="text" id="numberInput" /> 
 
 您选择了颜色:<div id="colorInfo"></div><br/>
 您选择了内存: <div id="memoryInfo"></div><br/>
 您输入了数量: <div id="numberInfo"></div><br/>
 
    <button id="nextBtn" disabled="true">请选择手机颜色和购买数量</button>
</body>
var colorSelect = document.getElementById('colorSelect'),
    numberInput = document.getElementById('numberInput'),
    memorySelect = document.getElementById('memorySelect'),
    colorInfo = document.getElementById('colorInfo'),
    numberInfo = document.getElementById('numberInfo'),
    memoryInfo = document.getElementById('memoryInfo'),
    nextBtn = document.getElementById('nextBtn');

var goods = { // 手机库存
    "red|32G": 3, // 红色 32G,库存数量为 3 
    "red|16G": 0,
    "blue|32G": 1,
    "blue|16G": 6
};

colorSelect.onchange = function() {
    var color = this.value,
        memory = memorySelect.value,
        stock = goods[color + '|' + memory];
    number = numberInput.value, // 数量
        colorInfo.innerHTML = color;

    if (!color) {
        nextBtn.disabled = true;
        nextBtn.innerHTML = '请选择手机颜色';
        return;
    }

    if (!memory) {
        nextBtn.disabled = true;
        nextBtn.innerHTML = '请选择内存大小';
        return;
    }

    if (((number - 0) | 0) !== number - 0) { // 输入购买数量是否为正整数
        nextBtn.disabled = true;
        nextBtn.innerHTML = '请输入正确的购买数量';
        return;
    }

    if (number > stock) { // 当前选择数量没有超过库存量
        nextBtn.disabled = true;
        nextBtn.innerHTML = '库存不足';
        return;
    }

    nextBtn.disabled = false;
    nextBtn.innerHTML = '放入购物车';
};

可以看到change事件里又加了一堆判断,而且在实际业务中,我们不仅仅是颜色下拉选项的change事件,我们要给所有的用户输入项都要加上相同的判定。

如果又新增更多的配置,这维护简直地狱。

引入中介者

我们可以利用封装的思维,可以将不变的和变的抽离出来,其中不变的就是整个if条件语句,这些都是可以公用的,我们将其封装到中介者对象上,让所有需要使用的地方都调用即可。

var goods = { // 手机库存
    "red|32G": 3,
    "red|16G": 0,
    "blue|32G": 1,
    "blue|16G": 6
};

var mediator = (function() {
    var colorSelect = document.getElementById('colorSelect'),
        memorySelect = document.getElementById('memorySelect'),
        numberInput = document.getElementById('numberInput'),
        colorInfo = document.getElementById('colorInfo'),
        memoryInfo = document.getElementById('memoryInfo'),
        numberInfo = document.getElementById('numberInfo'),
        nextBtn = document.getElementById('nextBtn');
        
    return {
        changed: function(obj) {
            var color = colorSelect.value, // 颜色
                memory = memorySelect.value, // 内存
                number = numberInput.value, // 数量
                stock = goods[color + '|' + memory]; // 颜色和内存对应的手机库存数量
                
            if (obj === colorSelect) { // 如果改变的是选择颜色下拉框
                colorInfo.innerHTML = color;
            } else if (obj === memorySelect) {
                memoryInfo.innerHTML = memory;
            } else if (obj === numberInput) {
                numberInfo.innerHTML = number;
            }
            
            if (!color) {
                nextBtn.disabled = true;
                nextBtn.innerHTML = '请选择手机颜色';
                return;
            }
            
            if (!memory) {
                nextBtn.disabled = true;
                nextBtn.innerHTML = '请选择内存大小';
                return;
            }
            
            if (((number - 0) | 0) !== number - 0) { // 输入购买数量是否为正整数
                nextBtn.disabled = true;
                nextBtn.innerHTML = '请输入正确的购买数量';
                return;
            }
            
            nextBtn.disabled = false;
            nextBtn.innerHTML = '放入购物车';
        }
    }
})();

// 事件函数:
colorSelect.onchange = function() {
    mediator.changed(this);
};
memorySelect.onchange = function() {
    mediator.changed(this);
};
numberInput.oninput = function() {
    mediator.changed(this);
};

现在如果我们再新增一个配置,处理起来也是很方便的。

var goods = { // 手机库存
    "red|32G|800": 3, // 颜色 red,内存 32G,cpu800,对应库存数量为 3 
    "red|16G|801": 0,
    "blue|32G|800": 1,
    "blue|16G|801": 6
};

var mediator = (function() {
    // 略
    var cpuSelect = document.getElementById('cpuSelect');
    return {
        change: function(obj) {
            // 略
            var cpu = cpuSelect.value,
                stock = goods[color + '|' + memory + '|' + cpu];
            if (obj === cpuSelect) {
                cpuInfo.innerHTML = cpu;
            }
            // 略
        }
    }
})();

我们只需要在中介者的公共方法中新增对应的逻辑,然后在需要新增事件的地方调用这个逻辑即可。

小结

中介者模式是迎合迪米特法则(最少知道原则)的一种实现,对象之间不知道彼此的存在,它们只通过中介者对象来相互影响,中介者通过公开接口的方式给其他对象使用,其他对象可以根据不同的接口传入不同参数,实现不同业务的处理。

中介者是可以直接操作对象的,但也因为将大量的公共逻辑都放在了中介者上,这导致它难以维护,而日常开发中,除非对象之间的耦合度确实导致调用和维护出现了困难,而且这些耦合度随着项目的变化呈指数增长,那么我们就可以考虑用中介者模式来重构代码,而不是过度堆砌模式和过度设计。

分类: JavaScript设计模式与开发实践 标签: JavaScript模式中介者模式

评论

暂无评论数据

暂无评论数据

目录