patterntypescriptModerate
Observer Pattern: Decouple Event Producers from Consumers
Viewed 0 times
observer patternbehavioral patternevent emitterpub subsubscribeunsubscribememory leak
Problem
An object (subject) needs to notify other objects of state changes without knowing who those objects are or how many there are. Direct coupling makes adding/removing listeners require modifying the subject.
Solution
The subject maintains a list of observers implementing a common
update interface. It calls update on all registered observers when state changes.interface Observer<T> {
update(payload: T): void;
}
class EventEmitter<T> {
private observers: Observer<T>[] = [];
subscribe(observer: Observer<T>): () => void {
this.observers.push(observer);
return () => this.unsubscribe(observer); // return unsubscribe fn
}
private unsubscribe(observer: Observer<T>): void {
this.observers = this.observers.filter(o => o !== observer);
}
protected notify(payload: T): void {
this.observers.forEach(o => o.update(payload));
}
}
class UserStore extends EventEmitter<{ userId: string; action: string }> {
login(userId: string) {
// ... login logic
this.notify({ userId, action: 'login' });
}
}Why
Observer decouples state management from side effects (logging, UI updates, analytics). Adding a new reaction requires only registering a new observer, not touching the subject.
Gotchas
- Memory leaks from unsubscribed observers are the most common bug. Always call the unsubscribe function when the observer is destroyed.
- Observers are called synchronously by default. A throwing observer blocks subsequent observers unless you wrap calls in try/catch.
- Avoid cascading notifications (an observer triggering another notification) — they can create infinite loops.
Revisions (0)
No revisions yet.