Skip to content
intermediate Phase 14 · TypeScript Design Patterns

Observer & Strategy Patterns (Advanced)

Implement behavioral patterns for event handling and algorithm selection.

1h
0 problems
Topic Progress 0%

Observer: Typed Event Flow

Observer: Typed Event Flow

The observer lets publishers notify subscribers without knowing who they are. Constrain it with a payload map so every event carries its own type:

type Events = {
  "order:placed": { id: string; total: number };
  "user:seen": { userId: string };
};

class Bus {
  private subs = new Map<keyof Events, ((p: any) => void)[]>();

  on<K extends keyof Events>(k: K, fn: (p: Events[K]) => void) {
    (this.subs.get(k) ?? this.subs.set(k, []).get(k)!).push(fn);
    return () => this.off(k, fn);
  }
}

Returning an unsubscribe function makes cleanup a one-liner in effects and request handlers.

Strategy: Algorithms Behind an Interface

Strategy: Algorithms Behind an Interface

Strategy extracts a swappable algorithm behind a contract. The function form is usually enough:

type Discount = (cents: number, tier: "bronze" | "gold") => number;

const rules: Record<string, Discount> = {
  flat: (c) => c - 500,
  tiered: (c, t) => (t === "gold" ? c * 0.8 : c * 0.95),
};

function charge(cents: number, tier: string, d: Discount) {
  return Math.max(0, d(cents, tier as "bronze" | "gold"));
}

Interface-based strategies fit stateful collaborators (a payment gateway, an encoder); function strategies fit stateless rules. Selection can be data-driven — a registry keyed by config — so adding an option means adding an entry, not editing a conditional.

Pitfalls and Interview Angles

Pitfalls and Interview Angles

Leaked listeners. Subscribing in a component or request path without unsubscribing grows memory and re-fires stale handlers; always dispose via the returned function (or AbortController for fetch-style listeners).

Error isolation. One throwing observer normally aborts the loop — wrap each handler so a bad subscriber cannot silence the rest.

Strategy sprawl. If strategies share hidden state or need the caller's internals, the abstraction is wrong: pass context as an argument or merge them.

Interview: sketch both patterns, then explain the difference the interviewer is probing — observer changes who reacts (many, dynamic), strategy changes how it computes (one, chosen per call).

Quiz

1. What should on(...) return to make cleanup reliable?

Question 1 options

2. Observer versus strategy: what does each vary?

Question 2 options

3. Why wrap observer handlers in try/catch during notify?

Question 3 options

Flashcards

Question

Observer pattern

Answer

Publisher notifies a list of subscribers it does not know; membership changes at runtime.

Question

Typed event map

Answer

Record of event name → payload type; on<K> then infers payload per event.

Question

Strategy pattern

Answer

One algorithm behind an interface or function type, swapped per call or per config.

Question

Listener leak

Answer

Subscribing without disposing; handlers pile up and fire on stale state.

Revision Notes

Key Takeaways

  • 1. Type the event map and return unsubscribe from subscribe
  • 2. Prefer function strategies for stateless rules, interfaces for collaborators
  • 3. Isolate handler errors so one subscriber cannot break delivery

Interview Tips

  • • Contrast observer with the mediator/publisher-subscriber split the interviewer may push on
  • • Show the registry form of strategy and explain why it beats an if/else chain

Cheat Sheet

on(k, fn) → typed payload via Events map, return off(); strategy = swappable function/interface selected per call; unsubscribe on dispose; try/catch per handler.

Continue Learning