Lets go by an example: consider you want to build two application:
- Chat application.
- Emergency ambulance operator application.
mediator
Building the chat application you will be choosing the mediator design pattern.
- The persons may be joining and leaving the chat at any given time, so it does not make any sense to keep direct reference between two persons chatting.
- We still need to facilitate a communication between two persons and allow them have a chat.
Why will we prefer the mediator? just have a look at its definition:
With the mediator pattern, communication between objects is
encapsulated within a mediator object. Objects no longer communicate
directly with each other, but instead communicate through the
mediator. This reduces the dependencies between communicating objects,
thereby reducing coupling.
How is the magic works? First we will create the chat mediator and make the persons objects register to it, so it will have two directional connection with every single person (the person can send message using the chat mediator cause it ha access to it, and the chat mediator will access the received method of the person object cause he also has access to it)
function Person(name) {
    let self = this;
    this._name = name;
    this._chat = null;
    this._receive(from, message) {        
        console.log("{0}: '{1}'".format(from.name(), message));
    }
    this._send(to, message) {
        this._chat.message(this, to, message);
    }
    return {
        receive: (from, message) => { self._receive(from, message) },
        send: (to, message) => { self._send(to, message) },
        initChat: (chat) => { this._chat = chat; },
        name: () => { return this._name; }
    }
}
function ChatMediator() {
    let self = this;
    this._persons = [];    
    return {
        message: function (from, to, message) {
            if (self._persons.indexOf(to) > -1) {
                self._persons[to].receive(from, message);
            }
        },
        register: function (person) {
            person.initChat(self);
            self._persons.push(person);
        }
        unRegister: function (person) {
            person.initChat(null);
            delete self._persons[person.name()];
        }
    }
};
//Usage:
let chat = new ChatMediator();
let colton = new Person('Colton');
let ronan = new Person('Ronan');
chat.register(colton);
chat.register(ronan);
colton.send(ronan, 'Hello there, nice to meet you');
ronan.send(colton, 'Nice to meet you to');
colton.send(ronan, 'Goodbye!');
chat.unRegister(colton);
observer
Building the 911 call application you will be choosing the observer design pattern.
- Each ambulance observerobject wishes to be informed when there is an emergency state, so he can drive the address and give help.
- The emergency operator observablekeep reference to each on of the ambulanceobserversand notify them when help is needed (or generating event).
Why will we prefer the observer? just have a look at its definition:
An object, called the subject, maintains a list of its dependents,
called observers, and notifies them automatically of any state
changes, usually by calling one of their methods.
function AmbulanceObserver(name) {
    let self = this;
    this._name = name;
    this._send(address) {
        console.log(this._name + ' has been sent to the address: ' + address);
    }
    return {
        send: (address) => { self._send(address) },
        name: () => { return this._name; }
    }
}
function OperatorObservable() {
    let self = this;
    this._ambulances = [];    
    return {
        send: function (ambulance, address) {
            if (self._ambulances.indexOf(ambulance) > -1) {
                self._ambulances[ambulance].send(address);
            }
        },
        register: function (ambulance) {
            self._ambulances.push(ambulance);
        }
        unRegister: function (ambulance) {
            delete self._ambulances[ambulance.name()];
        }
    }
};
//Usage:
let operator = new OperatorObservable();
let amb111 = new AmbulanceObserver('111');
let amb112 = new AmbulanceObserver('112');
operator.register(amb111);
operator.register(amb112);
operator.send(amb111, '27010 La Sierra Lane Austin, MN 000');
operator.unRegister(amb111);
operator.send(amb112, '97011 La Sierra Lane Austin, BN 111');
operator.unRegister(amb112);
The Differences:
- The chat mediatorhas two way communication between the persons objects (send and receive) wheres the operatorobservablehas only one way communication (It tell the ambulanceobserverto drive and finish).
- The chat mediatorcan make the persons objects interact between them (even if it not a direct communication), the ambulancesobserversonly registers to the operatorobservableevents.
- Each person object has a reference to the chat mediator, and also the chatmediatorkeep reference to the every one of the persons. Wheres the ambulanceobserverdoes not keep reference to the operatorobservable, only the operatorobservablekeep reference to every ambulanceobserver.