Mediator Software Design Pattern
Mediator Software Design Pattern

Situation: If you have multiple independent modules that work in a system (parts of a web page or a user interface system) and they must be kept seperate from eachother and aren’t allowed to communicate directly

Solution: Install a mediator and modules can communicate through mediator, which handles requests and directs the requests to the appropriate module

  • modules that need to communicate are known as colleagues

Step 1 – Page: colleague.js


// JavaScript Document
define(function() {
	'use strict';
	
	var Colleague = function (id, mediator) { // In this step, we will set up colleage constructor.  It accepts arguments of id and an instance of the mediator.  They are set as properties of the colleage instance, below...
		this.id = id;
		this.mediator = mediator;
	};
	
	Colleague.prototype.receiveMessage = function (message) { //now we extend the Colleage constructor with a method to receive messages
		console.log('Module', this.id, 'received message:', message); //receives the message as an argument and logs it to the console
		return true; //return true once the logging has occurred
	};
	
	Colleague.prototype.sendMessage = function (message, recipientId) { //extend class with method to send mesage, accepts the message and a recipient ID
		(recipientId) ? this.mediator.send(recipientId, message) : //if you are given a recipientID, then use the mediator send method to send the message to the prescribed colleague.  If recipientID is not supplied...
			this.mediator.broadcast(message, this); //use the mediator broadcast method to send the message to all colleagues.  We also pass the current id to the broadcast as to prevent the broadcast from sending the message to the colleague that sent it.
	};
	
	return {//rather than return the constructor like we usually do, we will be returning an object with a create method.  
		create: function (id, mediator) {
				var that = new Colleague (id, mediator); //Inside this method, we will initialize a new colleage and register it with mediator before passing back the new colleage
				
				mediator.register(that);
				
				return that;
		}
	};
});

Step 2 – Page: mediator.js


// JavaScript Document
define(function() {
	'use strict';
	
	var Mediator = function () { //set up mediator constructor
		this.colleagues = [];	//this will need to store all colleagues that it will be mediating for.  We don't know them all right now, so set this up as empty array
	};
	
	Mediator.prototype.register = function (colleague) { //this method will register a colleague with the mediator
		this.colleagues.push(colleague); //by pushing the current collegue into the colleagues array
	};
	
	Mediator.prototype.send = function (recipientId, message) { //this sets up the send method, which sends messages to individual colleagues.  Pass in recipiendId and message
		this.colleagues.some(function(colleague) { //now we iterate through some of the ids in the collegue array.  Some method works similiarly to forEach method in that it invokes a callback on items in an array.  It will keep invoking callback until return is true, then it stops.
			if (colleague.id === recipientId) { //this works because send method is only trying to send the message to the intended recipient, so once it finds it's destination, we don't have to keep parsing through the array
				return colleague.receiveMessage(message);	//it then returns the value from the receiveMessage method on the colleague, which will return true once we are one the target recipient
			}
		});
	};
	
	Mediator.prototype.broadcast = function (message, sender) { //sets up broadcast method, receive message to send
		this.colleagues.forEach(function(colleague) { //uses foreach method to iterate through entire array and run callback function
			if (colleague.id !== sender.id) { //the function sends the message to all colleagues except the colleague with a matching sender.id
				colleague.receiveMessage(message);	
			}
		});
	};
	
	return Mediator; //return constructor
});

Step 3 – Page: init.js


define(function(require) {
	'use strict';

	return {
		init: function() {
			var mediator, colleague1, colleague2, colleague3, //set up variables
				Mediator = require('mediator/mediator'), //set up object constructors
				colleague = require('mediator/colleague');
				
			mediator = new Mediator(); //create new instance of object
			colleague1 = colleague.create('colleague1', mediator); //create colleagues
			colleague2 = colleague.create('colleague2', mediator);
			colleague3 = colleague.create('colleague3', mediator);
			
			colleague1.sendMessage('Hey there', 'colleague2'); //send message from colleague 1 to 2
			colleague2.sendMessage('Hi colleague1', 'colleague1');
			colleague3.sendMessage('Hey guys!'); //broadcast a message with no recipient
		}
	};
});

Step 4 – Page: main.js


// JavaScript Document
require (
	['factory/init', 'pubSub/init', 'strategy/init', 'observer/init', 'COR/init', 'mediator/init'],
	function (factory, pubSub, strategy, observer, COR, mediator) {
			'use strict';
	
			var examples = {
					factory: factory,
					pubSub: pubSub,
					strategy: strategy,
					observer: observer,
					COR: COR,
					mediator: mediator
				};
			
			window.runExample = function (example) {
				examples[example].init();
			};
	}
);

Mediator Pattern is great for decoupling a group of modules that need to work together, but don’t need to know about eachother. Instead of every module depending on every other module, creating a tangled mess of dependencies, we can have them interact through the mediator.