Advanced Javascript Design Patterns: Part 1

Advanced Javascript Design Patterns: Part 1

Observer and PubSub Pattern

ยท

4 min read

Observer Pattern

The observer pattern is a design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any changes to its state. This allows multiple objects to be notified when the state of another object changes, without the objects being tightly coupled to one another.

An example of the observer pattern could be a weather app that displays the current temperature and weather conditions. The weather app's subject is the weather service, which maintains a list of observer objects, such as the temperature display and the weather conditions display. When the weather service receives updates from the weather station, it notifies the observer objects, which then update their displays accordingly.

import { EventEmitter } from "events";

interface WeatherData {
    temperature: number;
    conditions: string;
}

class WeatherService extends EventEmitter {
    constructor() {
        super();
    }

    updateWeather(data: WeatherData) {
        this.emit("weatherUpdate", data);
    }
}

class TemperatureDisplay {
    private weatherService: WeatherService;

    constructor(weatherService: WeatherService) {
        this.weatherService = weatherService;
        this.weatherService.on("weatherUpdate", this.update.bind(this));
    }

    update(data: WeatherData) {
        console.log(`Temperature: ${data.temperature}`);
    }
}

class WeatherConditionsDisplay {
    private weatherService: WeatherService;

    constructor(weatherService: WeatherService) {
        this.weatherService = weatherService;
        this.weatherService.on("weatherUpdate", this.update.bind(this));
    }

    update(data: WeatherData) {
        console.log(`Conditions: ${data.conditions}`);
    }
}

const weatherService = new WeatherService();
const temperatureDisplay = new TemperatureDisplay(weatherService);
const weatherConditionsDisplay = new WeatherConditionsDisplay(weatherService);

weatherService.updateWeather({ temperature: 72, conditions: "Sunny" });

A complex example of observer pattern is a stock market simulation system. The subject is a stock exchange, which maintains a list of observer objects, such as stock brokers, traders and investors. The exchange updates the stock prices and other relevant information of all the stocks being traded on the exchange. When the exchange receives updates from the stock market, it notifies the observer objects, which then update their displays accordingly.

PubSub Pattern

The pub-sub pattern, short for "publish-subscribe", is a design pattern in which an object, called the publisher, sends a message to a set of subscribers, without the publisher having knowledge of the subscribers or their identities. This allows for a loosely coupled system in which the publisher and subscribers can evolve independently of one another.

A common example of the pub-sub pattern is a social media platform, where users can publish posts, and other users can subscribe to specific users or topics to receive updates. The publisher in this case is the user who is posting, and the subscribers are the users who are following the poster or the topic. The platform itself acts as the message broker, forwarding the post to all subscribers who are interested in it.

class EventEmitter {
    private subscribers: { [event: string]: Array<(data: any) => void> } = {};

    subscribe<T>(event: string, callback: (data: T) => void) {
        if (!this.subscribers[event]) {
            this.subscribers[event] = [];
        }
        this.subscribers[event].push(callback);
    }

    unsubscribe<T>(event: string, callback: (data: T) => void) {
        if (this.subscribers[event]) {
            this.subscribers[event] = this.subscribers[event].filter(
                subscriber => subscriber !== callback
            );
        }
    }

    emit<T>(event: string, data: T) {
        if (this.subscribers[event]) {
            this.subscribers[event].forEach(subscriber => subscriber(data));
        }
    }
}

const eventEmitter = new EventEmitter();

const logTemperature = (temperature: number) => {
    console.log(`Temperature: ${temperature}`);
};

eventEmitter.subscribe("temperature", logTemperature);
eventEmitter.emit("temperature", 72);

In this example, the logTemperature function subscribes to the "temperature" event, and the eventEmitter object emits the "temperature" event with data 72 and the logTemperature function logs the temperature.

A complex example of pub-sub pattern is a smart city system where multiple sensor devices are placed all over the city. These sensors are publishing data like temperature, humidity, traffic density etc. to a central hub. There are multiple subscribers like traffic control system, weather forecasting system, air quality monitoring system etc. subscribing to these data streams. The sensor devices and subscriber systems can evolve independently of one another, and the central hub acts as the message broker, forwarding the data to all subscribers who are interested in it.

Key differences between the two patterns:

  • Observer pattern is typically implemented with a one-to-many relationship between the subject and observers, where the subject maintains a list of observers and notifies them when its state changes. Pub-sub pattern is implemented with a many-to-many relationship, where multiple publishers can send messages to multiple subscribers, and the subscribers are not aware of the identity of the publishers.

  • In observer pattern, the subject is aware of its observers and is responsible for notifying them when its state changes. In pub-sub pattern, the publisher is not aware of its subscribers and is only responsible for sending messages to a central message broker, which then forwards the message to the subscribers.

  • Observer pattern is typically used when the subject has a state that needs to be shared with multiple objects, and the subject and observers are closely related. Pub-sub pattern is typically used when there is a need for decoupling between the publisher and the subscriber, and when there are multiple publishers and subscribers that need to communicate with one another.

Conclusion

In conclusion, the observer pattern and the pub-sub pattern are both popular design patterns that are used to build loosely coupled systems in JavaScript.

While both patterns have their own advantages and use cases, it's important to choose the appropriate pattern based on the specific requirements of the application.

Did you find this article valuable?

Support Jay Desai by becoming a sponsor. Any amount is appreciated!

ย