前言:菜鸡也有梦想,而我的梦想就是进一个真正的互联网大厂。以前学习的时候没有系统的整理,从今天开始要保持每周写博客的习惯,希望自己可以有所成长。为了培养编程思维,决定从设计模式开始写起。我是通过读《Javascript设计模式与开发实践》来学习设计模式,并且将知识点和收获记录在博客中。
此文仅记录本人阅读《JavaScript设计模式与开发实践》的知识点与想法,感谢作者曾探大大写出这么好的一本书。如有冒犯,请联系本人:markcoder@outlook.com处理,请大家购买正版书籍。
1.中介者模式介绍
中介者模式的作用就是解除对象与对象之间的紧耦合关系。增加一个中介者对象后,所有的相关对象都通过中介者对象来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知中介者对象即可。
改造后
2.代码示例
这里还是使用书中的例子。
假设我们正在编写一个手机购买的页面,在购买流程中,可以选择手机的颜色以及输入购买数量,同时页面中有两个展示区域,分别向用户展示刚刚选择好的颜色和数量。还有一个按钮动态显示下一步的操作,我们需要查询该颜色手机对应的库存,如果库存数量少于这次的购买数量,按钮将被禁用并且显示库存不足,反之按钮可以点击并且显示放入购物车。
简单切一个页面出来。
2.1 不使用中介者模式
接下来将分别监听 colorSelect 的 onchange 事件函数和 numberInput 的 oninput 事件函数,然 后在这两个事件中作出相应处理。
let colorSelect = document.querySelector( '#colorSelect' ),
numberInput = document.querySelector( '#numberInput' ),
colorInfo = document.querySelector( '#colorInfo' ),
numberInfo = document.querySelector( '#numberInfo' ),
nextBtn = document.querySelector( '#nextBtn' );
const goods = { // 模拟从接口取得手机库存
"red": 3,
"blue": 6
};
// 监听颜色选择器改变
colorSelect.addEventListener('change', () => {
let color = colorSelect.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 = '放入购物车';
})
// 监听数量输入框改变
numberInput.addEventListener('change', () => {
let color = colorSelect.value, // 颜色
number = numberInput.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.disabled = false;
nextBtn.innerHTML = '放入购物车';
})
如果这时候,需求增加,又加入了CPU种类,那么又要扩充CPU选择框的函数,如果删除了某一种类的选择,又要深入到每一个函数去修改,非常的麻烦,每个节点对象都是耦合在一起的,改变或者增加任何一个节点对象,都要通知到与其相关的对象。
2.2使用中介者模式改写
const goods = { // 模拟从接口取得手机库存
"red": 3,
"blue": 6
};
const mediator = (() => {
let colorSelect = document.querySelector( '#colorSelect' ),
numberInput = document.querySelector( '#numberInput' ),
colorInfo = document.querySelector( '#colorInfo' ),
numberInfo = document.querySelector( '#numberInfo' ),
nextBtn = document.querySelector( '#nextBtn' );
return {
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;
}
nextBtn.disabled = false;
nextBtn.innerHTML = '放入购物车';
}
}
})();
// 事件函数:
colorSelect.addEventListener('change', () => {
mediator.changed( colorSelect );
});
numberInput.addEventListener('input', () => {
mediator.changed( numberInput );
});
可以想象,某天我们又要新增一些跟需求相关的节点,比如内存大小,那我们只需要稍稍改动 mediator 对象即可
新切一个页面
const goods = { // 模拟从接口取得手机库存
"red": 3,
"blue": 6
};
const mediator = (() => {
let colorSelect = document.querySelector( '#colorSelect' ),
memorySelect = document.querySelector( '#memorySelect' ), // 新增内存大小
numberInput = document.querySelector( '#numberInput' ),
colorInfo = document.querySelector( '#colorInfo' ),
numberInfo = document.querySelector( '#numberInfo' ),
nextBtn = document.querySelector( '#nextBtn' );
return {
changed: function( obj ){
let color = colorSelect.value, // 颜色
number = numberInput.value, // 数量
memory = memorySelect.value
if ( obj === colorSelect ){ // 如果改变的是选择颜色下拉框
colorInfo.innerHTML = color;
} else if ( obj === numberInput ){ // 如果改变的是选择颜色下拉框
numberInfo.innerHTML = number;
} else if ( obj === memorySelect ){ // 如果改变的是选择内存大小
memoryInfo.innerHTML = memory;
}
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.addEventListener('change', () => {
mediator.changed( colorSelect );
});
memorySelect.addEventListener('change', () => {
mediator.changed( memorySelect );
});
numberInput.addEventListener('input', () => { // 新增内存大小
mediator.changed( numberInput );
});
中介者模式可以非常方便地对模块或者对象进行解耦,但对象之间并非一定需要解耦。在实 际项目中,模块或对象之间有一些依赖关系是很正常的。毕竟我们写程序是为了快速完成项目交 付生产,而不是堆砌模式和过度设计。关键就在于如何去衡量对象之间的耦合程度。一般来说, 如果对象之间的复杂耦合确实导致调用和维护出现了困难,而且这些耦合度随项目的变化呈指数 增长曲线,那我们就可以考虑用中介者模式来重构代码。