Observer Pattern

The Observer Pattern is a type of object behavioral pattern that defines a one-to-many dependency between objects, so that when the state of one object changes, all its dependent objects are notified and updated automatically. The Observer Pattern is also known as the Publish-Subscribe Pattern, the Model-View Pattern, the Source-Listener Pattern, or the Dependents Pattern.

Description

The Observer Pattern establishes a dependency relationship between objects, where one object notifies other objects automatically when it changes, and the other objects respond accordingly. Therefore, the object that changes is called the subject, while the notified objects are called observers. A subject can have multiple observers, and these observers are not interrelated. Observers can be added or removed as needed, making the system easily extensible.

Advantages

  • The Observer Pattern can separate the presentation layer from the data logic layer and define a stable message update mechanism. It abstracts the update interface, allowing various different presentation layers to act as concrete observer roles.
  • The Observer Pattern establishes an abstract coupling between the subject and the observers.
  • The Observer Pattern supports broadcast communication.
  • The Observer Pattern complies with the requirements of the Open/Closed Principle.

Disadvantages

  • If a subject object has many direct and indirect observers, notifying all the observers can be time-consuming.
  • If there is a circular dependency between observers and the subject, the subject will trigger circular calls between them, which may lead to system crashes.
  • The Observer Pattern lacks a corresponding mechanism for observers to know how the subject object has changed, and they only know that the subject has changed.

Applicable Scenarios

  • An abstract model has two aspects, where one aspect depends on the other. By encapsulating these aspects in independent objects, they can change and be reused independently.
  • A change in one object will cause one or more other objects to change without knowing exactly how many objects will change, thereby reducing the coupling between objects.
  • An object must notify other objects without knowing which specific objects they are.
  • A trigger chain needs to be created in the system, where the behavior of object A will affect object B, and the behavior of object B will affect object C, and so on. The Observer Pattern can be used to create a chain trigger mechanism.

Implementation

class PubSub{ // Publish-Subscribe class
    constructor(){
        this.handlers = {};
    }

    on(key, handler) { // Subscribe
        if (!(key in this.handlers)) this.handlers[key] = [];
        this.handlers[key].push(handler);
    }

    off(key, handler) { // Unsubscribe
        const index = this.handlers[key].findIndex(item => item === handler);
        if (index < 0) return false;
        if (this.handlers[key].length === 1) delete this.handlers[key];
        else this.handlers[key].splice(index, 1);
        return true;
    }

    commit(key, ...args) { // Trigger
        if (!this.handlers[key]) return false;
        this.handlers[key].forEach(handler => handler.apply(this, args));
        return true;
    }
}

const eventBus = new PubSub();

/**
  Job seekers subscribe to some job boards, and they will be notified whenever there is a matching job opportunity
*/
class JobBoard{ // Job Bulletin Board
    subscribe(funct) {
        eventBus.on("job-sub", funct);
    }

    notify(){
        eventBus.commit("job-sub");
    }
}

class JobSeeker { // Job Seeker
    constructor(name) {
        this._name = name;
    }

    notify() {
        console.log(this._name, "has been notified of a new posting");
    }
}

(function(){
    var jonDoe = new JobSeeker("John Doe")
    var janeDoe = new JobSeeker("Jane Doe")
    var kaneDoe = new JobSeeker("Kane Doe")
var jobBoard = new JobBoard();
jobBoard.subscribe(() => jonDoe.notify());
jobBoard.subscribe(() => janeDoe.notify());
jobBoard.subscribe(() => kaneDoe.notify());

jobBoard.notify();
})();

Daily Question

https://github.com/WindrunnerMax/EveryDay

Reference

https://www.runoob.com/design-pattern/observer-pattern.html https://github.com/sohamkamani/javascript-design-patterns-for-humans#-observer https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/observer.html