中介者模式(Mediator)
通过中介者对象封装一系列对象之间的交互,使对象之间不再相互引用,降低他们之间的耦合。有时中介者对象也可改变对象之间的交互。
需求:为导航模块添加设置层用来控制显示隐藏
<style>
.icon {
width: 30px;
height: 30px;
fill: currentColor;
overflow: hidden;
}
.nav {
width: 300px;
height: 40px;
padding-top: 10px;
background-color: #fafafa;
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid #aaa;
}
.nav .nav-item {
flex: 1;
text-align: center;
}
.nav .nav-item span {
cursor: pointer;
position: relative;
display: inline-block;
}
.nav .nav-item span b {
position: absolute;
top: -5px;
right: -10px;
font-size: 8px;
padding: 1px 3px;
background-color: red;
color: #fff;
border-radius: 10px;
}
</style>
<body>
<label for="hide_nav"><input id="hide_nav" checked type="checkbox" />显示/隐藏导航</label>
<label for="hide_notice"><input id="hide_notice" checked type="checkbox" />显示/隐藏通知</label>
<nav class="nav">
<div id="home_nav" class="nav-item">
<span>
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-fangzi"></use>
</svg>
<b id="home_notice">10</b>
</span>
</div>
<div id="community_nav" class="nav-item">
<span>
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-shequ"></use>
</svg>
<b id="community_notice">99+</b>
</span>
</div>
<div id="me_nav" class="nav-item">
<span>
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-wode"></use>
</svg>
<b id="me_notice">24</b>
</span>
</div>
</nav>
<script src="./icons/iconfont.js"></script>
<script src="./index.js"></script>
</body>
// 中介者对象
var Mediator = (function () {
// 消息对象
var _messages = {
};
return {
_messages,
/**
* 订阅消息方法
* @param {string} type 消息名称
* @param {Function} action 消息回调函数
*/
register(type, action) {
// 如果该消息不存在,则建立该消息容器
if (!_messages[type]) {
_messages[type] = [];
}
// 存入新消息回调函数
_messages[type].push(action);
},
/**
* 发布消息方法
* @param {*} type 消息名称
*/
send(type) {
// 如果该消息已经被订阅
if (_messages[type]) {
// 遍历已存储的消息回调函数
_messages[type].forEach(action => action && action());
}
}
};
}());
/**
* 显示隐藏组件
* @param {string[]} ids DOM元素
* @param {boolean} isShow 显示隐藏
*/
const isShowNavWidget = function (ids, isShow) {
ids.forEach(id => {
const widget = document.getElementById(id);
widget.style.visibility = isShow ? 'visible' : 'hidden';
})
};
// 注册组件显示隐藏
(function () {
// 显示导航 --- 不需要显示通知
Mediator.register('showNav', function () {
isShowNavWidget(['home_nav', 'community_nav', 'me_nav'], true);
});
// 隐藏导航 --- 必须隐藏通知
Mediator.register('hideNav', function () {
isShowNavWidget(['home_nav', 'community_nav', 'me_nav'], false);
});
Mediator.register('hideNav', function () {
isShowNavWidget(['home_notice', 'community_notice', 'me_notice'], false);
});
// 显示通知 --- 必须显示导航
Mediator.register('showNotice', function () {
isShowNavWidget(['home_notice', 'community_notice', 'me_notice'], true);
});
Mediator.register('showNotice', function () {
isShowNavWidget(['home_nav', 'community_nav', 'me_nav'], true);
});
// 隐藏通知 --- 不需要隐藏导航
Mediator.register('hideNotice', function () {
isShowNavWidget(['home_notice', 'community_notice', 'me_notice'], false);
});
}());
// 设置层模块
(function () {
const hideNav = document.getElementById('hide_nav');
const hideNotice = document.getElementById('hide_notice');
// 显示隐藏所有导航
hideNav.onchange = function (e) {
// 显示导航 --- 不需要显示通知
if (hideNav.checked) {
Mediator.send('showNav');
}
// 隐藏导航 --- 必须隐藏通知
else {
hideNotice.checked = false;
Mediator.send('hideNav');
}
};
// 显示隐藏所有通知
hideNotice.onchange = function (e) {
// 显示通知 --- 必须显示导航
if (hideNotice.checked) {
hideNav.checked = true;
Mediator.send('showNotice');
}
// 隐藏通知 --- 不需要隐藏导航
else {
Mediator.send('hideNotice');
}
};
})();
console.log(Mediator);
特点:
- 与
观察者模式
相比- 同
观察者模式
一样,中介者模式
的主要业务也是通过模块间或者对象间的复杂通信,来解决模块间或对象间的耦合。 中介者对象
的本质是分装多个对象的交互,并且这些对象的交互一般都是在中介者内部实现的。观察者模式
中,订阅者是双向的,既可以是消息的发布者,也可以是消息的订阅者。中介者模式
中,订阅者是单向的,只能是消息的订阅者。而消息统一由中介者对象发布,所有的订阅者对象间接地被中介者管理。
- 同
- 与
外观模式
的封装特性
相比外观模式
封装的目的是为了提供更简单的易用接口,而不会添加其他功能。中介者模式
对多个对象交互地封装,且这些对象一般处于同一层面上,并且封装的交互在中介者内部。