Observer design pattern

In the observer pattern, a subject maintains a collection of interested observers. Whenever there is a state change in which the observers are interested, they are notified so that each has a chance to update itself.

For example, the subject might be a live dataset which gets presented by different displays (the observers). Whenever the data changes, the displays get notified so they can update their presentation. In our initial use of this pattern, the subject is used to notify animated objects (the observers) of elapsed time so they can update themselves.

We’ll use class notation to define a Subject class.

class Subject {

    // a subject maintains a set of registered observers
    constructor() {
        this.observers = new Set();
    }

    // register observer obs with subject
    register(obs) {
        if (!this.observers.has(obs))
            this.observers.add(obs);
    }

    // unregister observer obj from subject
    unregister(obs) {
        if (this.observers.has(obs))
            this.observers.delete(obs);
    }

    // notify every registered observer of data
    notify(data) {
        this.observers.forEach(function (obs) {obs.update(data);});
    }
}

An observer is any object with an update property bound to a one-argument function. The argument is the data in which the observer is interested. Data may be a simple value or an object the observer can query for the information it needs to update itself.

To demonstrate the pattern, we define a possible observer class:

 class Observer {
    constructor(name) {
        this.name = name;
    }
  
    update(data) {
        console.log(`${this.name} has just been notified of ${data}`);
    }
}

In this example, an Observer gets constructed with a string name. Whenever an observer receives an update message with the argument data, it prints a message that it has been notified of data. A sample transcript:

// construct a subject
let subject = new Subject();

// construct two observers
let earth = new Observer('Earth');
let saturn = new Observer('Saturn');

// register observer earth
subject.register(earth);

// notify the subject of morning
subject.notify('morning'); // Earth has just been notified of morning

// register observer Saturn
subject.register(saturn);

// notify the subject of afternoon
subject.notify('afternoon'); // Earth has just been notified of afternoon
                             // Saturn has just been notified of afternoon

// deregister observer earth
subject.unregister(earth);

// notify the subject of night
subject.notify('night'); // Saturn has just been notified of night