Module 4 / Behavioral patterns
Module 4 · Core Patterns

Behavioral patterns

Define how objects communicate, distribute responsibilities, and encapsulate algorithms.

0/4 lessons

Observer

Learn

The Observer establishes a one-to-many dependency: when the subject changes state, all registered observers are notified and updated automatically. The subject doesn't know the concrete types of its observers — only that they implement a notification interface.

This is the foundation of event-driven architectures, reactive programming, and pub/sub systems. DOM event listeners, RxJS observables, Redux store subscriptions, and Vue's reactivity system are all Observer variants.

class EventEmitter { private listeners: Map<string, Function[]> = new Map(); on(event: string, fn: Function) { this.listeners.get(event)?.push(fn) ?? this.listeners.set(event, [fn]); } emit(event: string, ...args: unknown[]) { this.listeners.get(event)?.forEach(fn => fn(...args)); } }
Observers can cause cascading updates and memory leaks if subscriptions aren't cleaned up. Always unsubscribe when the observer's lifecycle ends.
Practice
Loading…
Recall0/1
Recall

What problem does the Observer pattern solve?

Strategy

Learn

The Strategy extracts varying algorithms into separate classes that share a common interface. The context holds a reference to a strategy and delegates to it — swapping strategies changes behavior without modifying the context.

This replaces conditional logic (if/else, switch) with polymorphism. Instead of a giant function with branches for each algorithm, each branch becomes its own class implementing the strategy interface.

interface SortStrategy { sort(data: number[]): number[]; } class QuickSort implements SortStrategy { sort(d) { … } } class MergeSort implements SortStrategy { sort(d) { … } } class DataProcessor { constructor(private strategy: SortStrategy) {} process(data: number[]) { return this.strategy.sort(data); // ← delegates to strategy } }
Strategy is one of the most practical patterns day-to-day. Anytime you see a function with multiple algorithmic branches selected by a parameter, that's a candidate for extraction into strategies.
Practice
Loading…
Recall0/1
Recall

What does the Strategy pattern replace?

Command

Learn

The Command encapsulates a request as an object — bundling the action, its parameters, and the receiver into a single callable entity. This decouples the invoker (who triggers the action) from the receiver (who performs it).

Because commands are objects, you can queue them, log them, serialize them, support undo/redo, or schedule them for later execution. Text editors, task schedulers, and transactional systems rely heavily on this pattern.

interface Command { execute(): void; undo(): void; } class PasteCommand implements Command { constructor(private editor: Editor, private clipboard: string) {} execute() { this.editor.insert(this.clipboard); } undo() { this.editor.delete(this.clipboard.length); } } // Invoker doesn't know what the command does history.push(command); command.execute();
Command turns actions into data. Once an operation is an object, you gain queuing, undo, replay, and macro capabilities almost for free.
Practice
Loading…
Recall0/1
Recall

What capability does Command unlock that direct method calls cannot?

Iterator

Learn

The Iterator provides a way to traverse a collection without exposing its internal structure (array, linked list, tree, hash map). The client gets a uniform traversal interface regardless of how the collection stores its elements.

Modern languages have largely absorbed this pattern into the language itself: JavaScript's `for...of`, Python's `iter()`/`next()`, Java's `Iterable`, C#'s `IEnumerable`. You rarely implement Iterator from scratch anymore — but understanding it explains why these constructs work.

// Modern JS: Iterator protocol built-in const range = { from: 1, to: 5, [Symbol.iterator]() { let current = this.from; return { next: () => current <= this.to ? { value: current++, done: false } : { done: true } }; } }; for (const n of range) console.log(n); // 1, 2, 3, 4, 5
Even though you won't hand-roll iterators often, recognizing the pattern helps you understand generators, async iteration, streams, and custom iterable protocols.
Practice
Loading…
Recall0/1
Recall

Why has the Iterator pattern been largely absorbed into modern programming languages?