Observer Pattern: One Change, Many Reactions

Observer turns a state change into a broadcast so multiple dependents can react without the source knowing their concrete implementations.

What is the Observer pattern?

The Observer pattern is a behavioral design pattern where an object (the subject) keeps a list of dependents (observers) and notifies them automatically whenever its state changes. The subject knows only that subscribers implement a notification contract — it never knows who they are or what they do with the event.

This one-to-many, push-based relationship is the backbone of event systems everywhere: DOM events, RxJS, Node's EventEmitter, and every UI framework's reactivity model are Observer at heart. The pattern decouples "something happened" from "here is everything that must react," so new reactions can be added without touching the event source.

The logic, step by step

Problem

One event must update several features, but directly calling every dependent makes the source tightly coupled and fragile.

Rule

Let observers subscribe to a subject, then notify the current subscriber list whenever relevant state changes.

Run
  1. OBSERVERS register interest in a specific source of change.
  2. SUBJECT changes state and emits a notification to subscribers.
  3. EACH OBSERVER decides independently how to respond to the event.
Output

Reactions can be added or removed without teaching the event source about every downstream feature.

Observer pattern example in TypeScript

TypeScript
type PriceListener = (symbol: string, price: number) => void;

class PriceFeed {
  private listeners = new Set<PriceListener>();

  subscribe(listener: PriceListener): () => void {
    this.listeners.add(listener);
    return () => this.listeners.delete(listener); // unsubscribe handle
  }

  update(symbol: string, price: number): void {
    for (const listener of this.listeners) listener(symbol, price);
  }
}

const feed = new PriceFeed();

const stopChart = feed.subscribe((s, p) => chart.plot(s, p));
feed.subscribe((s, p) => { if (p > 2400) alerts.send(`${s} above 2400`); });
feed.subscribe((s, p) => auditLog.write({ symbol: s, price: p }));

feed.update('XAU', 2412.5); // chart redraws, alert fires, audit row written
stopChart();                // chart stops reacting; others continue
One price update fans out to a chart, an alert rule, and an audit log. The feed knows none of them — it only walks its subscriber list.

Run it in the real world

A price update can refresh the chart, trigger an alert, and write an audit record while the price service knows none of those details.

When to use it — and when not to

Reach for Observer when

  • One state change must trigger several independent reactions, and the list of reactions changes over time.
  • The event source must not depend on downstream features (core domain emitting, UI and integrations listening).
  • You are building push-based flows: live data, notifications, cache invalidation, UI reactivity.

Skip it when

  • There is exactly one, stable consumer — a direct method call is clearer and easier to trace.
  • Ordering between reactions matters. Observer makes execution order an implementation detail, which becomes a bug factory.

Command pattern — Observer broadcasts "state changed" to whoever is listening; Command hands a specific request to a specific invoker. Observers are passive reactions, commands are deliberate instructions.

Frequently asked questions

What is a real-world example of the Observer pattern?

A newsletter is the classic one: readers subscribe, the publisher sends one issue, every current subscriber receives it, and anyone can unsubscribe without the publisher changing how it publishes. In code: DOM addEventListener, RxJS subjects, and webhook fan-out all follow the same shape.

What is the difference between Observer and Pub/Sub?

In classic Observer, subscribers register directly with the subject, so the two sides share a reference. Pub/Sub inserts a broker (an event bus or message queue) between them, so publisher and subscriber never meet. Pub/Sub is Observer with an extra layer of decoupling.

What are the downsides of the Observer pattern?

Forgotten subscriptions leak memory, chains of observers triggering other subjects make behavior hard to trace, and one throwing observer can silently break the notification loop unless the subject isolates errors per listener.