中介者模式的核心在于接触多个对象之间错综复杂的关系,使得每个对象只需要和中介者进行通信,而对象与其他对象之间的联系则交由中介者传达。
一、场景
现在有场景,某购物网站的商品详情页中的添加到购物车模块,需要包含有如下的逻辑
1)选择商品规格,然后填写购买数量
2)如果购买数量大于可售数量,则加入购物车
按钮置灰
3)如果没有填写购买数量,则按钮提示请填写数量
实现如下:
选择颜色:
<select id="colorSelect">
<option value="red">红色</option>
<option value="blue">蓝色</option>
</select>
输入数量:
<input type="text" id="numberInput">
当前选择了:<span id="colorInfo"></span><span id="numberInfo"></span>
<button id="nextBtn" disabled="true">请选择手机颜色和购买数量</button>
js代码如:
const colorSelect = $('#colorSelect'),
numberInput = $('#numberInput'),
colorInfo = $('#colorInfo'),
numberInfo = $('#numberInfo'),
nextBtn = $('#nextBtn')
const goods = {
red: 3,
blue: 6
}
colorSelect.onchange = function() {
let 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.disable = false
nextBtn.innerHTML = '加入购物车'
}
而此时,除了选择颜色的select变更时需要对各个状态做出响应之外,在数量改变的时候也需要做出响应,如:
numberInput.oninput = function() {
let color = colorSelect.value,
number = this.value,
stock = goods[color]
numberInfo.innerHTML = number
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.disable = false
nextBtn.innerHTML = '加入购物车'
}
二、难题
在上例中,我们可以发现,当select和input的输入值都发生了变化的时候,需要重复处理一样的逻辑,而麻烦的不仅仅是这里。我们可以画出模块间的耦合关系图:
可以看到,仅仅是这么一个简单的逻辑下,就已经产生了如此错综复杂的联系。这样子一来,耦合度高,很容易造成代码的难以维护。
而中介者模式,则是为了解决这种问题而产生的。中介者对象作为所有对象的枢纽中心,它接收来自其他对象的通知,并管理和其他对象的关系,如此一来,可以实现其他对象之间的解耦。引入中介者对象的关系图如:
由于实现了这种方式的解耦,我们此后就需要维护中介者对象即可。其他对象彼此之间都不关心是否存在彼此,它们只需要跟中介者打交道即可,而它们的联系,则都由中介者对象处理。
三、解决问题
所以,现在我们可以引入中介者对象来解决开头的问题了:
const mediator = (function() {
const changed = function(obj) {
let color = colorSelect.value,
number = numberInput.value
if (obj === colorSelect) {
colorInfo.innerHTML = color
} else if (obj === numberInput) {
numberInfo.innerHTML = number
}
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.disable = false
nextBtn.innerHTML = '加入购物车'
}
return { changed }
})()
colorSelect.onchange = function() {
mediator.changed(this)
}
numberInput.onchange = function() {
mediator.changed(this)
}
如此一来,当我们有一天需要新增新的select,也就仅仅需要在中介者对象里加入少量的代码,并且指定一个新的onchange
函数,就可以完成需求了。好处是明显的
四、总结
1)中介者模式解决了多个对象之间彼此紧密耦合的问题,通过引入中介者,多个对象之间能够实现不关心彼此。而只需要考虑和中介者对象通信即可,大大降低了多个对象之间的耦合。
2)但是缺点也是有的,首先中介者对象本身可能就是一个很复杂的对象,多个对象之间耦合的复杂性虽然通过中介者对象解耦了,但是反过来增加的则是中介者对象的复杂性。此外,还造成了系统中需要多引入一个中介者对象的问题。
3)中介者模式仍然是具有很大的价值的,是否采用中介者模式,主要取决于我们对对象之间耦合程度的要求