TypeScript Observer Design Pattern

Ibrahim sengun
3 min readJan 26, 2024

--

What is observer design pattern?

The observer design pattern is a behavioral design pattern that provides the ability to build a subscription mechanism for objects. With this mechanism, the system gains the ability to observe the objects’ life cycle.

There are several terminologies in the observer design pattern. These are:

  • Publisher: It notifies the event of the observed object.
  • Subscriber: It is the interface that defines the outline of the notification mechanism.
  • Concrete Subscribers: These are the classes that handle the outline defined in the subscriber interface.
  • Client: This refers to the application or function that communicates with the system.

When should the observer design pattern be used?

The observer design pattern can be used when there is a need to know the state of a specific object and its changes within the system. By observing these changes, system can notify other objects and make necessary adjustments to the itself.

How to implement observer design pattern in TypeScript

Let’s apply the Observer design pattern to TypeScript. First, let’s imagine a scenario where we are dealing with a shipping system, and we want to add a notifier feature to it with the aim of notifying customers and stores about their products. To build a system like this means that whenever there is a new entry or a change in our system, clients should be informed. To achieve this, we first decide to design a system that constantly checks our objects for changes. However, this design causes us to waste an increased amount of resources. Because of this, we decide to employ the Observer design pattern and build a subscriber mechanism. Giving the choice for objects to subscribe to the events that they are interested in, this way, instead of watching and tracking the whole system, observers can now choose what to observe and for how long to observe.

Observer design pattern diagram

Observer design pattern diagram

Observer design pattern code

// Subscriber interface
interface ISubscriber {
update(message: string): void;
}

// Concrete Subscriber
class Warehouse implements ISubscriber {
private name: string;

constructor(name: string) {
this.name = name;
}

update(message: string): void {
console.log(`Warehouse ${this.name} received update: ${message}`);
}
}

// Concrete Subscriber
class Customer implements ISubscriber {
private name: string;

constructor(name: string) {
this.name = name;
}

update(message: string): void {
console.log(`Customer ${this.name} received update: ${message}`);
}
}

// Publisher
class ShippingSubject {
private subscribers: ISubscriber[] = [];

subscribe(Subscriber: ISubscriber): void {
this.subscribers.push(Subscriber);
}

unsubscribe(Subscriber: ISubscriber): void {
this.subscribers = this.subscribers.filter(s => s !== Subscriber);
}

notify(message: string): void {
this.subscribers.forEach(Subscriber => Subscriber.update(message));
}
}

// Client
const shippingSystem = new ShippingSubject();

const warehouse1 = new Warehouse('Warehouse A');
const customer1 = new Customer('Customer X');
const customer2 = new Customer('Customer Y');

shippingSystem.subscribe(warehouse1);
shippingSystem.subscribe(customer1);
shippingSystem.subscribe(customer2);

/*
Warehouse Warehouse A received update: Package shipped from the supplier.
Customer Customer X received update: Package shipped from the supplier.
Customer Customer Y received update: Package shipped from the supplier.
*/
shippingSystem.notify('Package shipped from the supplier.');

shippingSystem.unsubscribe(customer1);

shippingSystem.notify('Package arrived at the local distribution center.');
/*
Warehouse Warehouse A received update: Package arrived at the local distribution center.
Customer Customer Y received update: Package arrived at the local distribution center.
*/

--

--