Design Patterns

Sefism.

Chapter 04

Behavioural patterns: requests and events

Patterns for passing requests, events and state between objects without tying them tightly together.

Chain of Responsibility

Also called middleware, handler chain, pipeline

What
Intent: pass a request along a chain of handlers until one handles it or the chain ends.
Why
When: several independent checks or steps apply to a request, such as authentication, rate limiting and validation middleware.
TypeScript
type Handler = (req: Req, next: () => void) => void;

const chain: Handler[] = [authenticate, rateLimit, validate];
function run(req: Req, i = 0) {
  if (i < chain.length) chain[i](req, () => run(req, i + 1));
}

Command

Also called action object, undo

What
Intent: turn a request into an object with everything needed to perform it, and often to undo it.
Why
When: you need undo and redo, queues, scheduled jobs, macros or a log of actions to replay.
TypeScript
interface Command { run(): void; undo(): void; }

class AddText implements Command {
  constructor(private doc: Doc, private text: string) {}
  run() { this.doc.append(this.text); }
  undo() { this.doc.trimEnd(this.text.length); }
}
history.push(cmd); cmd.run();

Iterator

Also called cursor, generator

What
Intent: walk through a collection one item at a time without exposing how it is stored.
Why
When: callers should loop over a tree, a paginated API or a custom structure with a plain for loop. Most languages build it in.
TypeScript
class Paged implements Iterable<Row> {
  *[Symbol.iterator]() {
    for (let p = 1; ; p++) {
      const rows = fetchPage(p);
      if (!rows.length) return;
      yield* rows;
    }
  }
}
for (const row of new Paged()) show(row);

Mediator

Also called hub, controller

What
Intent: objects talk through one mediator instead of referring to each other directly.
Why
When: many components interact in tangled ways, such as form fields that enable and fill each other, or chat room users.
Example
A booking form's date picker, slot list and price box each report changes to a form controller, which decides what the others should show.

Watch out

Letting the mediator absorb all logic until it becomes a god object.

Memento

Also called snapshot

What
Intent: capture an object's internal state as a snapshot so it can be restored later, without exposing its internals.
Why
When: you need undo, drafts, checkpoints or rollback in editors, games and forms.
TypeScript
class Editor {
  private text = '';
  save() { return { text: this.text } as const; }
  restore(m: { text: string }) { this.text = m.text; }
}

Observer

Also called publish-subscribe, pub/sub, event listener, listener

What
Intent: when one object changes, all objects subscribed to it are notified automatically.
Why
When: many parts react to one event, such as UI updates, webhooks and domain events. addEventListener and RxJS are built on it.
TypeScript
class Emitter<T> {
  private subs = new Set<(v: T) => void>();
  on(fn: (v: T) => void) {
    this.subs.add(fn);
    return () => this.subs.delete(fn);   // unsubscribe
  }
  emit(v: T) { this.subs.forEach((fn) => fn(v)); }
}

Watch out

Forgetting to unsubscribe, which leaks memory and fires handlers on screens that are gone.

04 · Behavioural patterns: requests and events4 / 9