中介者模式
当很多模块之间的耦合度或依赖度过高时,我们考虑使用中介者模式来实现,各个模块之间不相互通信,而是通过中介者来完成。
通过下面的示例来体会使用中介者模式和不使用中介者模式之间的差异。
示例 口罩购买
原型图及分析
-
没有选择口罩种类,按钮文本为:请选择口罩种类
-
没有选择口罩数量,按钮文本为: 请选择口罩数量
-
选择口罩种类和数量后需要进行以下校验
- 库存校验,库存不足,按钮文本为:库存不足
- 限购校验,口罩购买数量大于5时,按钮文本为:最多购买5只
-
口罩种类和口罩数量文本显示已经选择的。
不使用中介者模式实现
// 口罩种类
const MASKS = {
"KN95": { text: "KN95口罩", count: 3 },
"N95": { text: "N95口罩", count: 2 },
"NORMAL": { text: "普通医用口罩", count: 7 }
}
// 最大购买数量
const CAN_BUY_MAX_COUNT = 5
const getDom = id => document.getElementById(id)
const selType = getDom('type')
const selCount = getDom('count')
const infoType = getDom('info-type')
const infoCount = getDom('info-count')
const btn = getDom('btn')
selType.onchange = function () {
if (!this.value) { // 未选择
infoType.innerText = '未选择'
btn.value = "请选择口罩种类"
return
} else {
infoType.innerText = MASKS[this.value]['text']
}
// 是否选择口罩数量
let count = selCount.value * 1;
if (!count) {
btn.value = "请选择口罩数量"
}
if (count && this.value) {
if (count > MASKS[this.value]['count']) {
btn.value = "库存不足"
}
if (count > CAN_BUY_MAX_COUNT) {
btn.value = "超过限购只数5"
} else {
btn.value = "加入购物车"
btn.style['pointer-events'] = 'all'
}
}
}
selCount.onchange = function () {
// 是否选择数量
let count = this.value * 1
let type = selType.value
if (!type) { //未选择类型
btn.value = "请选择口罩种类"
}
if (!count) { // 未选择种类
infoCount.innerText = '未选择'
if (type) btn.value = "请选择口罩数量"
}
if (count && type) { // 库存和限购校验
infoCount.innerText = this.value
if (MASKS[type]['count'] < count) {
btn.value = "库存不足"
return
}
if (count > CAN_BUY_MAX_COUNT) {
btn.value = "超过限购只数5"
} else {
btn.value = "加入购物车"
btn.style['pointer-events'] = 'all'
}
}
}
btn.onclick = () => alert('加入购物车成功')
从上面的的代码可以看到数量变化需要对种类选择进行判断,种类选择变化需要对数量进行判断,从而在页面上显示正确的值(这里主要是指按钮文本)。这里只是两个选择框之间彼此耦合,如果耦合的模块更多,比如又增加了一个发货地,在数量或种类发生变化时还需要对发货地进行判断,这样会造成代码耦合度过高,样板代码过多,类似于这种业务,我们可以考虑中介者模式来实现。
中介者模式中,模块之间不相互通信,彼此之间没有任何联系,所有的业务都通过中介者来完成。a模块不关心b模块,同样b模块也不关心a模块,a和b模块只需要告诉中介者我发生了什么,然后中介者进行相应的处理。
使用中介者模式实现
const store = {
changed(type) {
if (type === selType) {
infoType.innerText = MASKS[type.value] ?
MASKS[type.value]['text'] : '未选择'
}
if (type === selCount) {
infoCount.innerText = type.value ?type.value: '未选择'
}
let count = selCount.value
if (!selType.value) {
btn.value = "请选择口罩种类"
return
}
if (!count) {
btn.value = "请选择口罩数量"
return
}
if (count && selType.value) { // 库存和限购校验
if (MASKS[selType.value]['count'] < count) {
btn.value = "库存不足"
return
}
if (count > CAN_BUY_MAX_COUNT) {
btn.value = "超过限购只数5"
} else {
btn.value = "加入购物车"
btn.style['pointer-events'] = 'all'
}
}
}
}
selCount.onchange = function() {store.changed(this)}
selType.onchange =function() { store.changed(this)}
btn.onclick = () => alert('加入购物车成功')
框架中的中介者模式
常见的vuex或者redux可以认为是中介者模式实现的,组件间的通信通过store中介者来实现,a组件不关心还有哪些其他组件使用了我的数据,b组件也不关心a组件是否使用了相同的数据。a组件的数据发生变化后只需要告诉中介者(
store
)我的数据发生了变化,然后中介者收到变化后进行相应的业务处理(更新所有使用该数据的组件数据)