JavaScript设计模式———中介者模式
中介者模式: 对象和对象之间借助第三方中介者进行通信。
中介者模式的作用就是解除对象与对象之间的紧耦合关系。
增加一个中介者对象后,所有的相关对象都通过中介者对象来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知中介者对象即可。中介者使各对象之间耦合松散,而且可以独立地改变它们之间的交互。中介者模式使网状的多对多关系变成了相对简单的一对多关系。
例子:
假设我们正在编写一个手机购买的页面,在购买流程中,可以选择手机的颜色以及输入购买数量,同时页面中有两个展示区域,分别向用户展示刚刚选择好的颜色和数量。还有一个按钮动态显示下一步的操作,我们需要查询该颜色手机对应的库存,如果库存数量少于这次的购买数量,按钮将被禁用并且显示库存不足,反之按钮可以点击并且显示放入购物车。
<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>
<script>
// 假设我们已经提前从后台获取到了所有颜色手机的库存量
var goods = { // 手机库存
"red": 3,
"blue": 6
};
var colorSelect = document.getElementById('colorSelect'), // 颜色选择框
numberInput = document.getElementById('numberInput'), // 数量输入框
colorInfo = document.getElementById('colorInfo'), // 颜色显示区
numberInfo = document.getElementById('numberInfo'), // 数字显示区
nextBtn = document.getElementById('nextBtn'); // 按钮
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 = '放入购物车';
};
</script>
上面例子得问题:
在目前的实现中,每个节点对象都是耦合在一起的,改变或者增加任何一个节点对象,都要通知到与其相关的对象。
中介者模式
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);
};
总结
中介者模式是迎合迪米特法则的一种实现。迪米特法则也叫最少知识原则,是指一个对象应该尽可能少地了解另外的对象(类似不和陌生人说话)。
中介者模式使各个对象之间得以解耦,以中介者和对象之间的一对多关系取代了对象之间的网状多对多关系。各个对象只需关注自身功能的实现,对象之间的交互关系交给了中介者对象来实现和维护。
中介者模式也存在一些缺点:
最大的缺点是系统中会新增一个中介者对象,因为对象之间交互的复杂性,转移成了中介者对象的复杂性,使得中介者对象经常是巨大的。中介者对象自身往往就是一个难以维护的对象。
中介者模式可以非常方便地对模块或者对象进行解耦,但对象之间并非一定需要解耦。在实际项目中,模块或对象之间有一些依赖关系是很正常的。毕竟我们写程序是为了快速完成项目交付生产,而不是堆砌模式和过度设计。关键就在于如何去衡量对象之间的耦合程度。一般来说,如果对象之间的复杂耦合确实导致调用和维护出现了困难,而且这些耦合度随项目的变化呈指数增长曲线,那我们就可以考虑用中介者模式来重构代码。