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

AdvantageDisadvantage
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 runtimeCan cause memory leaks (if observers are not unsubscribed)