Объяснить, что представляет собой паттерн «медиатор» достаточно просто на примере следующей аналогии — представьте себе контроль трафика в аэропорту: все решения о том, какие самолеты могут взлетать или садиться, принимает диспетчер. Для этого, все сообщения, исходящие от самолетов, поступают в башню управления, вместо того, чтобы пересылаться между самолетами напрямую. Такой централизованный контроллер — это и есть ключ к успеху нашей системы. Это и есть «медиатор».

Медиатор применяется в системах, где взаимодействие между модулями может быть весьма сложными, но, в то же время, хорошо определенными. Если вы полагаете, что связи между модулями вашей системы будут постоянно расти и усложняться, то, возможно, вам стоит добавить центральный элемент управления. Паттерн «медиатор» отлично подходит для этой роли.

Медиатор выступает в качестве посредника в общении между различными модулями, инкапсулируя их взаимодействие. Кроме того, этот шаблон проектирования, предотвращая прямое взаимодействие различных компонентов системы, способствует ослаблению связей в коде. В нашей системе он также помогает в решении проблем, связанных с зависимостями модулей.

Какие еще преимущества существуют у «медиатора»? К примеру, медиатор позволяет каждому модулю функционировать абсолютно независимо от других компонентов системы, что приводит к большей гибкости. Если вам ранее уже приходилось использовать паттерн «наблюдатель» в роли системы доставки событий между различными частями в вашей системе, то вам не составит труда разобраться с медиатором.

Давайте посмотрим на модель взаимодействия модулей и медиатора:

domfotopo.org

Мы можем рассматривать модули, как «издателей», публикующих события. Медиатор же является и «издателем» и «подписчиком» одновременно. В примере, Module 1 посылает сообщение, предполагающее некоторую реакцию, медиатору. Затем, медиатор, получив сообщение, уведомляет другие модули об определенных действиях, которые необходимо выполнить для завершения задачи. Module 2 выполняет необходимые Module 1 действия, и сообщает о результате обратно, в медиатор. В это же время, медиатор запускает Module 3 для логгирования поступающих сообщений.

Обратите внимание: здесь нет прямого взаимодействия между модулями. Если в Module 3 произойдет ошибка или, к примеру, он просто перестанет работать, то медиатор, теоретически, может приостановить выполнение задач в других модулях, затем перезапустить Module 3 и продолжить работу, практически не влияя на работу всей системы. Такая слабая связанность модулей является одним из самых сильных преимуществ паттерна «медиатор», который я вам предлагаю использовать.

Посмотрим на его преимущества:

Уменьшает связывание модулей, добавляя посредника — центральный элемент управления. Это позволяет модулям отправлять и слушать сообщения, не затрагивая остальной части системы. Сообщения могут быть обработаны любым количеством модулей сразу.

Благодаря слабой связанности кода, внедрение новой функциональности происходит существенно легче.

И недостатки:

Модули больше не могут взаимодействовать напрямую. Использование медиатора приводит к небольшому падению производительности — такова природа слабой связанности — становится достаточно трудно определить реакцию системы, отталкиваясь только от событий, происходящих в ней.

Наконец, системы с высокой связанностью кода являются обычно источником всевозможных проблем, решением которых может стать уменьшение связанности.

Пример: одна из возможных реализаций паттерна «медиатор», основанная на работе @rpflorence

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;
}
};
}());

И два примера использования реализации, написанной выше:

//Pub/sub on a centralized mediator
mediator.name = "tim";
mediator.subscribe('nameChange', function(arg) {
console.log(this.name);
this.name = arg;
console.log(this.name);
});
mediator.publish('nameChange', 'david'); //tim, david
//Pub/sub via third party mediator
var obj = {name: 'sam'};
mediator.installTo(obj);
obj.subscribe('nameChange', function(arg) {
console.log(this.name);
this.name = arg;
console.log(this.name);
});
obj.publish('nameChange', 'john'); //sam, john

Ссылки по теме:
Stoyan Stefanov — Page 168, JavaScript Patterns
HB Stone — Шаблоны проектирования JavaScript: Медиатор
NVince Huston — Шаблон Медиатора (не относится JavaScript, но кратко)

Рекомендуем почитать:
Книги по JavaScript на ЛАБИРИНТ