Observer Pattern
The Observer Pattern is a behavioral design pattern.
On this page
Observer Pattern in JavaScript
1. Definition
The Observer Pattern is a behavioral design pattern.
Its purpose is to define a one-to-many relationship between objects: when one object (the subject/publisher) changes state, all of its dependent objects (observers/subscribers) are notified and updated automatically.
Sources:
2. When Should You Use the Observer Pattern?
- When one object needs to notify several other objects about a state change.
- When you need to reduce direct coupling between objects.
3. Steps to Implement the Observer Pattern
-
Review the business logic and split it into two parts:
- The core, independent functionality becomes the publisher (subject).
- The rest is turned into subscriber (observer) classes.
-
Declare a subscriber interface:
- It should have at least an update (or notify) method.
-
Declare a publisher interface:
- It needs two methods: adding a subscriber to the list, and removing a subscriber from the list.
- The publisher only interacts with subscribers through the subscriber interface.
-
Decide where to store the subscription list and implement the subscription methods:
- Usually this goes in an abstract class that implements the publisher interface directly, for concrete publishers to inherit from.
- If retrofitting onto an existing class hierarchy, you can use composition: put the subscription logic in a separate object and have publishers use it.
-
Create concrete publisher classes:
- When an important event occurs, the publisher notifies all of its registered subscribers.
-
Implement the update method in concrete subscriber classes:
- Subscribers usually need context data about the event, which can be passed as parameters to update.
- Alternatively, the publisher can pass itself into update, letting subscribers pull the data they need.
-
The client creates the necessary subscribers and registers them with the appropriate publishers.
Basic Implementation Example
interface Store {
attach(customer: Customer): void;
detach(customer: Customer): void;
notify(): void;
}
class FptStore implements Store {
public newPhoneName: string = "";
private customers: Customer[] = [];
public attach(customer: Customer): void {
const isExist = this.customers.includes(customer);
if (isExist) {
return console.log("Customer has been attached already.");
}
this.customers.push(customer);
console.log(`Attached a customer: ${customer.name}.`);
}
public detach(customer: Customer): void {
const customerIndex = this.customers.indexOf(customer);
if (customerIndex === -1) {
return console.log(`Customer not found: ${customer.name}.`);
}
this.customers = this.customers.filter((c) => c !== customer);
console.log(`Detached a customer: ${customer.name}.`);
}
public notify(): void {
for (const customer of this.customers) {
customer.update(this);
}
}
public newPhoneRelease(phoneName: string): void {
this.newPhoneName = phoneName;
console.log(`New phone released: ${phoneName}`);
this.notify();
}
}
interface Customer {
name: string;
update(store: Store): void;
}
class IFanCustomer implements Customer {
public name: string;
constructor(name: string) {
this.name = name;
}
public update(store: Store): void {
if (store instanceof FptStore) {
console.log(
`${this.name}: Notified about new phone release - ${store.newPhoneName}.`
);
}
}
}
const fptStore = new FptStore();
const customer1 = new IFanCustomer("Alice");
const customer2 = new IFanCustomer("Bob");
fptStore.attach(customer1);
fptStore.attach(customer2);
fptStore.newPhoneRelease("iPhone 15");
fptStore.detach(customer1);
fptStore.newPhoneRelease("Samsung Galaxy S24");
4. Pros & Cons
Pros:
- Easy to extend - add a new observer without touching the publisher's code.
- Reduces coupling between publisher and subscribers.
Cons:
- If not managed well, the number of observers can become hard to control.
- Too many observers can start to hurt performance.
5. Real-World Applications
- Event systems: DOM events, pub/sub in frontend frameworks (React, Vue, Angular, etc.).
- MVVM/MVC patterns (the View listens for changes to the Model).
- Notification systems, data binding.
Sources:
