Last updated: Apr 29, 2026
Observer
The Observer pattern establishes a one-to-many relationship between a subject and its observers — when the subject’s state changes, all registered observers are notified and can react accordingly.
It is often used in event systems (e.g. DOM events), reactive UI updates, and pub/sub messaging.
Example in TypeScript
type Observer<T> = (value: T) => void;
class Subject<T> {
private observers = new Set<Observer<T>>();
subscribe(observer: Observer<T>) {
this.observers.add(observer);
}
unsubscribe(observer: Observer<T>) {
this.observers.delete(observer);
}
notify(value: T) {
for (const observer of this.observers) {
observer(value);
}
}
}
type AnalyticsEvent = { action: string; page: string };
const analytics = new Subject<AnalyticsEvent>();
const googleAnalytics: Observer<AnalyticsEvent> = (event) =>
console.log(`[GA] ${event.action} on ${event.page}`);
const customAnalytics: Observer<AnalyticsEvent> = (event) =>
console.log(`[Custom] ${event.action} on ${event.page}`);
const emailAnalytics: Observer<AnalyticsEvent> = (event) =>
console.log(`[Email] ${event.action} on ${event.page}`);
analytics.subscribe(googleAnalytics);
analytics.subscribe(customAnalytics);
analytics.subscribe(emailAnalytics);
analytics.notify({ action: "click", page: "/home" });
// [GA] click on /home
// [Custom] click on /home
// [Email] click on /home
analytics.unsubscribe(emailAnalytics);
analytics.notify({ action: "scroll", page: "/about" });
// [GA] scroll on /about
// [Custom] scroll on /about
Trade-Offs
| Advantage | Disadvantage |
|---|---|
| Loose coupling between subject and observers (separation of concerns) | Notifying all subscribers can become expensive if handlers are complex or there are too many subscribers (running notifications in parallel can help) |
| Easy to add and remove observers at runtime | Can cause memory leaks (if observers are not unsubscribed) |