介绍

中介者模式(Mediator),用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

主要内容来自:http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/#mediatorpatternjavascript

正文

软件开发中,中介者是一个行为设计模式,通过提供一个统一的接口让系统的不同部分进行通信。一般,如果系统有很多子模块需要直接沟通,都要创建一个中央控制点让其各模块通过该中央控制点进行交互。中介者模式可以让这些子模块不需要直接沟通,而达到进行解耦的目的。

打个比方,平时常见的机场交通控制系统,塔台就是中介者,它控制着飞机(子模块)的起飞和降落,因为所有的沟通都是从飞机向塔台汇报来完成的,而不是飞机之前相互沟通。中央控制系统就是该系统的关键,也就是软件设计中扮演的中介者角色。

我们先用伪代码来理解一下:

// 如下代码是伪代码,请不要过分在意代码
// 这里app命名空间就相当于扮演中介者的角色
var app = app || {}; // 通过app中介者来进行Ajax请求
app.sendRequest = function ( options ) {
return $.ajax($.extend({}, options);
} // 请求URL以后,展示View
app.populateView = function( url, view ){
$.when(app.sendRequest({url: url, method: 'GET'})
.then(function(){
//显示内容
});
} // 清空内容
app.resetView = function( view ){
view.html('');
} 在JavaScript里,中介者非常常见,相当于观察者模式上的消息Bus,只不过不像观察者那样通过调用pub/sub的形式来实现,而是通过中介者统一来管理,让我们在观察者的基础上来给出一个例子: var mediator = (function () {
// 订阅一个事件,并且提供一个事件触发以后的回调函数
var subscribe = function (channel, fn) {
if (!mediator.channels[channel]) mediator.channels[channel] = [];
mediator.channels[channel].push({ context: this, callback: fn });
return this;
}, // 广播事件
publish = function (channel) {
if (!mediator.channels[channel]) return false;
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0, l = mediator.channels[channel].length; i < l; i++) {
var subscription = mediator.channels[channel][i];
subscription.callback.apply(subscription.context, args);
}
return this;
}; return {
channels: {},
publish: publish,
subscribe: subscribe,
installTo: function (obj) {
obj.subscribe = subscribe;
obj.publish = publish;
}
}; } ()); 调用代码,相对就简单了: (function (Mediator) { function initialize() { // 默认值
mediator.name = "dudu"; // 订阅一个事件nameChange
// 回调函数显示修改前后的信息
mediator.subscribe('nameChange', function (arg) {
console.log(this.name);
this.name = arg;
console.log(this.name);
});
} function updateName() {
// 广播触发事件,参数为新数据
mediator.publish('nameChange', 'tom'); // dudu, tom
} initialize(); // 初始化
updateName(); // 调用 })(mediator); 中介者和观察者 到这里,大家可能迷糊了,中介者和观察者貌似差不多,有什么不同呢?其实是有点类似,但是我们来看看具体的描述:
观察者模式,没有封装约束的单个对象,相反,观察者Observer和具体类Subject是一起配合来维护约束的,沟通是通过多个观察者和多个具体类来交互的:每个具体类通常包含多个观察者,而有时候具体类里的一个观察者也是另一个观察者的具体类。 而中介者模式所做的不是简单的分发,却是扮演着维护这些约束的职责。 中介者和外观模式 很多人可能也比较迷糊中介者和外观模式的区别,他们都是对现有各模块进行抽象,但有一些微妙的区别。 中介者所做的是在模块之间进行通信,是多向的,但外观模式只是为某一个模块或系统定义简单的接口而不添加额外的功能。系统中的其它模块和外观模式这个概念没有直接联系,可以认为是单向性。 完整的例子 再给出一个完整的例子: <!doctype html>
<html lang="en">
<head>
<title>JavaScript Patterns</title>
<meta charset="utf-8">
</head>
<body>
<div id="results"></div>
<script>
function Player(name) {
this.points = 0;
this.name = name;
}
Player.prototype.play = function () {
this.points += 1;
mediator.played();
};
var scoreboard = { // 显示内容的容器
element: document.getElementById('results'), // 更新分数显示
update: function (score) {
var i, msg = '';
for (i in score) {
if (score.hasOwnProperty(i)) {
msg += '<p><strong>' + i + '<\/strong>: ';
msg += score[i];
msg += '<\/p>';
}
}
this.element.innerHTML = msg;
}
}; var mediator = { // 所有的player
players: {}, // 初始化
setup: function () {
var players = this.players;
players.home = new Player('Home');
players.guest = new Player('Guest');
}, // play以后,更新分数
played: function () {
var players = this.players,
score = {
Home: players.home.points,
Guest: players.guest.points
}; scoreboard.update(score);
}, // 处理用户按键交互
keypress: function (e) {
e = e || window.event; // IE
if (e.which === 49) { // 数字键 "1"
mediator.players.home.play();
return;
}
if (e.which === 48) { // 数字键 "0"
mediator.players.guest.play();
return;
}
}
}; // go!
mediator.setup();
window.onkeypress = mediator.keypress; // 30秒以后结束
setTimeout(function () {
window.onkeypress = null;
console.log('Game over!');
}, 30000);
</script>
</body>
</html> 总结 中介者模式一般应用于一组对象已定义良好但是以复杂的方式进行通信的场合,一般情况下,中介者模式很容易在系统中使用,但也容易在系统里误用,当系统出现了多对多交互复杂的对象群时,先不要急于使用中介者模式,而是要思考一下是不是系统设计有问题。 另外,由于中介者模式把交互复杂性变成了中介者本身的复杂性,所以说中介者对象会比其它任何对象都复杂。 同步与推荐 本文已同步至目录索引:深入理解JavaScript系列 深入理解JavaScript系列文章,包括了原创,翻译,转载等各类型的文章,如果对你有用,请推荐支持一把,给大叔写作的动力。

深入理解JavaScript系列(36):设计模式之中介者模式的更多相关文章

  1. 深入理解JavaScript系列(50):Function模式(下篇)

    介绍 本篇我们介绍的一些模式称为初始化模式和性能模式,主要是用在初始化以及提高性能方面,一些模式之前已经提到过,这里只是做一下总结. 立即执行的函数 在本系列第4篇的<立即调用的函数表达式> ...

  2. 深入理解JavaScript系列(49):Function模式(上篇)

    介绍 本篇主要是介绍Function方面使用的一些技巧(上篇),利用Function特性可以编写出很多非常有意思的代码,本篇主要包括:回调模式.配置对象.返回函数.分布程序.柯里化(Currying) ...

  3. 深入理解JavaScript系列

    转自http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html 深入理解JavaScript系列(1):编写高质量JavaScript代码 ...

  4. 深入理解JavaScript系列(转自汤姆大叔)

    深入理解JavaScript系列文章,包括了原创,翻译,转载,整理等各类型文章,如果对你有用,请推荐支持一把,给大叔写作的动力. 深入理解JavaScript系列(1):编写高质量JavaScript ...

  5. [转]深入理解JavaScript系列

    文章转自:汤姆大叔-深入理解JavaScript系列文章 深入理解JavaScript系列文章,包括了原创,翻译,转载,整理等各类型文章,如果对你有用,请推荐支持一把,给大叔写作的动力. 深入理解Ja ...

  6. [转载]深入理解JavaScript系列 --汤姆大叔

    深入理解JavaScript系列文章,包括了原创,翻译,转载,整理等各类型文章,如果对你有用,请推荐支持一把,给大叔写作的动力. 深入理解JavaScript系列(1):编写高质量JavaScript ...

  7. 深入理解JavaScript系列(转载)

    深入理解JavaScript系列 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点 深入理解JavaScript系列(2):揭秘命名函数表达式 深入理解JavaSc ...

  8. 深入理解JavaScript系列(38):设计模式之职责链模式

    介绍 职责链模式(Chain of responsibility)是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象 ...

  9. 深入理解JavaScript系列(30):设计模式之外观模式

    介绍 外观模式(Facade)为子系统中的一组接口提供了一个一致的界面,此模块定义了一个高层接口,这个接口值得这一子系统更加容易使用. 正文 外观模式不仅简化类中的接口,而且对接口与调用者也进行了解耦 ...

随机推荐

  1. 2018数学建模A题优秀论文:高温作业专用服装设计

    高温作业专用服装设计 摘 要 本文针对多层材料的高温作业服装的传热问题进行研究,综合考虑多种传热方式建立传热模型,并以此模型为基础解决了服装设计中各层材料最佳厚度的问题. 对于问题一,要求在热物性系数 ...

  2. Jenkins项目部署使用教程-----03节点添加

    1)添加节点 系统管理——>管理节点——>新建节点 进入配置界面 点ok进入配置界面配置,——>高级 点击save保存,进入节点,点击Launch agent使得jenkins服务器 ...

  3. EOS 智能合约 plublic key 转换

      在做一个EOS 的action接口时,定义如下: void setbplist(const account_name bp_name, const uint64_t bp_time, const ...

  4. js 对象 浅拷贝 和 深拷贝

    网上发现一个比较好的博客 阮一峰的感觉很不错推荐大家看看. http://www.ruanyifeng.com/blog/it/javascript/ 接下来看一下这两个拷贝方法 1.浅拷贝 拷贝就是 ...

  5. 【Jquery】jquery刷新页面(局部及全页面刷新)

    下面介绍全页面刷新方法:有时候可能会用到window.location.reload()刷新当前页面.parent.location.reload()刷新父亲对象(用于框架)opener.locati ...

  6. js 获取滚动条事件

    function getScroll() { return { left: window.pageXOffset || document.documentElement.scrollLeft || d ...

  7. JQ模拟触发事件

    jQuery 事件 - trigger() 方法 jQuery 事件参考手册 实例 触发 input 元素的 select 事件: $("button").click(functi ...

  8. 【算法笔记】B1026 程序运行时间

    1026 程序运行时间 (15 分) 要获得一个 C 语言程序的运行时间,常用的方法是调用头文件 time.h,其中提供了 clock() 函数,可以捕捉从程序开始运行到 clock() 被调用时所耗 ...

  9. P4578 [FJOI2018]所罗门王的宝藏

    传送门 考虑一个位置答案传递性,如果某个位置的红宝石转动确定了,那么会引起连锁反应: 如图,绿色的转动确定了,那么那两个蓝色的转动也确定了 自己手玩一下,发现如果有解那么随便找一个开始然后一路玩下去最 ...

  10. Poj:1064 : :Cable master (假定一个解并判断是否可行)(二分搜索答案)

    Description Inhabitants of the Wonderland have decided to hold a regional programming contest. The J ...