JavaScript 中介者模式
前言
中介者模式(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;
}
// 略
}
}
})();
我们只需要在中介者的公共方法中新增对应的逻辑,然后在需要新增事件的地方调用这个逻辑即可。
小结
中介者模式是迎合迪米特法则(最少知道原则)的一种实现,对象之间不知道彼此的存在,它们只通过中介者对象来相互影响,中介者通过公开接口的方式给其他对象使用,其他对象可以根据不同的接口传入不同参数,实现不同业务的处理。
中介者是可以直接操作对象的,但也因为将大量的公共逻辑都放在了中介者上,这导致它难以维护,而日常开发中,除非对象之间的耦合度确实导致调用和维护出现了困难,而且这些耦合度随着项目的变化呈指数增长,那么我们就可以考虑用中介者模式来重构代码,而不是过度堆砌模式和过度设计。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据