design_patterns_behavioral 33 Q&As

Design Patterns Behavioral FAQ & Answers

33 expert Design Patterns Behavioral answers researched from official documentation. Every answer cites authoritative sources you can verify.

unknown

33 questions
A

Strategy defines family of algorithms, encapsulates each, makes them interchangeable. Algorithm varies independently from clients using it. Use when: (1) Multiple related classes differ only in behavior, (2) Need different variants of algorithm, (3) Want to hide algorithm implementation details. Pattern: interface Strategy {execute(data)}; class ConcreteStrategyA implements Strategy {execute(data) {/* algorithm A */}}. Context: class Context {constructor(private strategy: Strategy) {} doWork(data) {return this.strategy.execute(data);}}. Usage: const context = new Context(new QuickSortStrategy()); context.doWork(array). Benefits: Eliminates conditional statements (if/switch), runtime algorithm selection, follows Open/Closed Principle. Example: Payment strategies (CreditCard, PayPal, Crypto), compression algorithms (ZIP, RAR, GZIP), validation strategies (Email, Phone, Password). Directly implements Open/Closed Principle from SOLID.

99% confidence
A

Observer defines one-to-many dependency where subject notifies observers automatically when state changes. Use when: (1) Change to one object requires changing others, (2) Object should notify others without knowing who they are (loose coupling), (3) Event handling, pub/sub systems. Pattern: interface Observer {update(data)}; class Subject {private observers: Observer[] = []; attach(o: Observer) {this.observers.push(o);} notify(data) {this.observers.forEach(o => o.update(data));}}. Example: Stock ticker - PriceSubject notifies ChartObserver, AlertObserver, LogObserver when price changes. Benefits: Loose coupling (subject doesn't know observers), dynamic relationships (attach/detach runtime). Problems: Memory leaks (forgot to detach), unexpected updates (cascade effects). Modern alternatives: EventEmitter (Node.js), RxJS Observables, browser Events. Use for: Event systems, MVC (model notifies views), real-time updates.

99% confidence
A

Command encapsulates request as object, allowing parameterization, queuing, logging, and undo operations. Use when: (1) Need to queue operations, (2) Support undo/redo, (3) Log changes for audit/replay, (4) Decouple sender from receiver. Pattern: interface Command {execute(); undo?()}; class SaveCommand implements Command {constructor(private doc: Document) {} execute() {this.doc.save();} undo() {this.doc.revert();}}. Invoker: class Button {constructor(private command: Command) {} click() {this.command.execute();}}. Benefits: Decouples invoker from receiver, extensible (add commands without changing invoker), supports undo/macro commands. Example: Text editor (copy/paste/bold commands), transaction systems (rollback), task schedulers (queue jobs). Pattern enables: Command history for undo, macro recording, progress tracking. Use for: UI actions, transactional systems, job queues, event sourcing.

99% confidence
A

Template Method defines skeleton of algorithm in base class, letting subclasses override specific steps without changing structure. Use when: (1) Common algorithm structure with varying implementations, (2) Want to prevent subclasses from changing algorithm structure, (3) Reduce code duplication across similar classes. Pattern: abstract class DataProcessor {process() {this.readData(); this.processData(); this.saveData();} protected abstract readData(); protected abstract processData(); protected saveData() {/* default /}}. Subclasses: class CSVProcessor extends DataProcessor {readData() {/ CSV specific */}}. Benefits: Reuses common code (DRY), enforces algorithm structure, follows Hollywood Principle ('don't call us, we'll call you'). Problems: Rigidity (fixed structure), fragile base class. Modern alternative: Composition with Strategy pattern (more flexible). Use for: Frameworks (define processing pipelines), data importers, test fixtures.

99% confidence
A

Chain of Responsibility passes request along chain of handlers. Each handler decides to process or pass to next. Use when: (1) Multiple objects can handle request, (2) Handler not known beforehand, (3) Want to issue request to one of several objects without specifying receiver. Pattern: interface Handler {setNext(handler: Handler); handle(request)}; class ConcreteHandler implements Handler {private next: Handler; setNext(h: Handler) {this.next = h; return h;} handle(req) {if (this.canHandle(req)) return this.process(req); if (this.next) return this.next.handle(req);}}. Chain: authHandler.setNext(validationHandler).setNext(businessLogicHandler). Benefits: Decouples sender from receivers, dynamic chain (add/remove handlers), single responsibility (each handler does one thing). Example: Middleware (Express.js), event bubbling (DOM), logging levels (debug→info→warn→error). Use for: Request processing pipelines, validation chains, approval workflows.

99% confidence
A

State allows object to alter behavior when internal state changes. Object appears to change class. Use when: (1) Object behavior depends on state, (2) Large conditionals based on state, (3) State-specific behavior scattered across methods. Pattern: interface State {handle(context: Context)}; class Context {private state: State; setState(s: State) {this.state = s;} request() {this.state.handle(this);}}. States: class OpenState implements State {handle(c) {/* open behavior */; c.setState(new ClosedState());}}. Example: TCP connection states (Established, Listen, Closed), document states (Draft, Review, Published), order states (Pending, Paid, Shipped). Benefits: Eliminates conditionals, single responsibility (one class per state), easy to add states. Alternative: State machine libraries (XState). Use for: Workflows, game character states, connection management, UI component states (loading, error, success).

99% confidence
A

XState is actor-based state management library for complex app logic with visual state charts. Pattern: import {createMachine, interpret} from 'xstate'; const authMachine = createMachine({id: 'auth', initial: 'idle', states: {idle: {on: {LOGIN: 'loading'}}, loading: {invoke: {src: loginAPI, onDone: {target: 'authenticated', actions: 'saveUser'}, onError: 'error'}}, authenticated: {on: {LOGOUT: 'idle'}}, error: {on: {RETRY: 'loading'}}}}). React integration: import {useMachine} from '@xstate/react'; const [state, send] = useMachine(authMachine); <button onClick={() => send('LOGIN')}>Login. Benefits: (1) Visual state charts (see all states/transitions), (2) Impossible states prevented (no loading+authenticated), (3) TypeScript support excellent, (4) Testing simplified (pure functions). XState Store (Dec 2024): Lightweight alternative combining Zustand simplicity with state machine structure. Use cases: Multi-step forms (checkout), authentication flows, async workflows, game state. 2024: Preferred over Redux for complex state transitions. Avoid for: Simple toggle/counter state (use useState).

99% confidence
A

XState models behavior as finite states and transitions (state machine), Redux models state as single object updated by reducers (state container), Context models state sharing without props drilling (DI mechanism). XState: Explicit states (loading, success, error) with transitions, impossible states prevented, visual state charts, best for complex workflows. Redux: Any state shape, actions update via reducers, time-travel debugging, best for global app state. Context: Share values across tree, no built-in updates (use with useState/useReducer), best for theming/auth/i18n. When to use each: XState for multi-step processes (checkout, wizard, auth flow), Redux for large apps with complex data flow + devtools, Context for simple shared values. XState prevents bugs: Can't be loading AND authenticated simultaneously, transitions explicit (authenticated → logout → idle). Redux allows any state: Can accidentally set {loading: true, user: {...}} simultaneously. Modern 2025: XState for workflows, Zustand/Jotai for simple global state, Context for injection. Don't use Redux for new projects unless need time-travel or existing ecosystem.

99% confidence
A

Iterator provides way to access elements of aggregate sequentially without exposing underlying representation. JavaScript has built-in iterator protocol. Pattern: interface Iterator {next(): {value: T, done: boolean}}; interface Iterable {Symbol.iterator: Iterator}. Implementation: class Collection implements Iterable {*Symbol.iterator {for (const item of this.items) yield item;}}. Usage: for (const item of collection) {} or [...collection]. Benefits: Uniform iteration interface, hides internal structure, multiple iterators (parallel traversal). Built-in: Array, Map, Set, String all iterable. Custom iterator: class Range {constructor(start, end) {this.start = start; this.end = end;} *Symbol.iterator {for (let i = this.start; i <= this.end; i++) yield i;}}. Use for: Custom collections, lazy sequences, infinite sequences (generators). Modern: Async iterators (Symbol.asyncIterator) for streams.

99% confidence
A

Mediator defines object that encapsulates how set of objects interact. Promotes loose coupling by keeping objects from referring to each other explicitly. Use when: (1) Many-to-many object interactions become complex, (2) Want to reuse objects independently, (3) Centralize control logic. Pattern: class Mediator {notify(sender, event) {/* coordinate */}}; class Component {constructor(private mediator: Mediator) {} doSomething() {this.mediator.notify(this, 'event');}}. Example: Chat room - users don't send messages directly, ChatRoomMediator distributes. Dialog box - Submit button doesn't validate fields directly, DialogMediator coordinates. Benefits: Reduces dependencies (components know only mediator), centralizes interaction logic, easier to understand interactions. Problems: Mediator can become God Object (too much responsibility). Use for: UI components coordination, chat systems, air traffic control, game event managers. Modern alternative: Event bus pattern.

99% confidence
A

Memento captures and externalizes object's internal state without violating encapsulation, allowing object to be restored later. Use for: (1) Undo/redo functionality, (2) Snapshots/checkpoints, (3) Transaction rollback. Pattern: class Memento {constructor(private state: any) {} getState() {return this.state;}}; class Originator {private state; save(): Memento {return new Memento(this.state);} restore(m: Memento) {this.state = m.getState();}}; class Caretaker {private mementos: Memento[] = []; backup(o: Originator) {this.mementos.push(o.save());} undo(o: Originator) {o.restore(this.mementos.pop());}}. Benefits: Preserves encapsulation (no getters for internal state), simplifies originator (caretaker manages history). Example: Text editor undo, game save points, form draft saving. Modern: Immutable data structures (Redux, Immer) enable easy snapshots. Use Memento for: Version control systems, database snapshots, configuration rollback.

99% confidence
A

Visitor separates algorithm from object structure it operates on. Allows adding new behaviors to existing class hierarchy without altering code. Use when: (1) Object structure stable but operations change frequently, (2) Need unrelated operations on objects, (3) Avoid polluting classes with many operations. Pattern: interface Visitor {visitConcreteA(el: ConcreteA); visitConcreteB(el: ConcreteB)}; interface Element {accept(visitor: Visitor)}; class ConcreteA implements Element {accept(v: Visitor) {v.visitConcreteA(this);}}. TypeScript example: interface ASTNode {accept(visitor: Visitor)}; class NumberNode implements ASTNode {constructor(public value: number) {} accept(v: Visitor) {return v.visitNumber(this);}}. Visitors: class TypeChecker implements Visitor {visitNumber(node: NumberNode) {return 'number';}}; class CodeGenerator implements Visitor {visitNumber(node: NumberNode) {return node.value.toString();}}. Benefits: Single Responsibility (operations separated), Open/Closed (add operations without modifying elements), gather related operations. Problems: Adding element types requires updating all visitors (violates OCP for elements). 2025 use cases: Compiler ASTs (TypeScript compiler uses extensively), report generation (PDF/XML/JSON exporters), linter rules (ESLint, Biome). Modern approach: Combine with pattern matching for cleaner syntax. Use for: Tree traversal, multi-format exporters, validation pipelines, transformation chains.

99% confidence
A

Interpreter defines representation for grammar and interpreter to interpret sentences. Use when: (1) Grammar is simple, (2) Efficiency not critical, (3) Want to execute/evaluate language statements. Pattern: interface Expression {interpret(context: Context): any}; class TerminalExpression implements Expression {interpret(c) {/* leaf - no recursion */}}; class NonterminalExpression implements Expression {constructor(private left: Expression, private right: Expression) {} interpret(c) {return this.left.interpret(c) + this.right.interpret(c);}}. Example: Math expressions - '2 + 3 * 4' becomes tree of AddExpr(Number(2), MultiplyExpr(Number(3), Number(4))). Benefits: Easy to change grammar (add expressions), grammar explicit in code, extensible (add new operations). Problems: Complex grammars become unmaintainable (classes explode), performance poor for large grammars. 2025 modern alternatives: (1) PEG parsers (Parsing Expression Grammars) - unambiguous, efficient top-down parsing, (2) Parser combinators (higher-order functions compose parsers) - PetitParser framework widely used, (3) Packrat parsers - verified interpreters with memoization. Use Interpreter for: Simple DSLs (config languages, search queries), formula evaluators, rule engines. Don't use for: Programming languages (use ANTLR, Tree-sitter), complex parsers (use PEG parser generators). TypeScript example: class NumberExpr {constructor(private val: number) {} interpret() {return this.val;}}; class AddExpr {constructor(private l: Expression, private r: Expression) {} interpret() {return this.l.interpret() + this.r.interpret();}}. 2024-2025 trend: Parser combinators preferred over classic Interpreter pattern for flexibility and composability.

99% confidence
A

RxJS provides powerful implementation of Observer pattern with operators. Pattern: import {Subject} from 'rxjs'; const subject = new Subject(); subject.subscribe({next: (data) => console.log(data), error: (err) => console.error(err), complete: () => console.log('done')}); subject.next('event 1'); subject.next('event 2'); subject.complete(). Benefits over classic Observer: (1) Operators for transformation (map, filter, debounce), (2) Built-in error handling, (3) Memory management (unsubscribe), (4) Async support (async/await). Types: Subject (hot, multicast), BehaviorSubject (stores latest value), ReplaySubject (replays N events), AsyncSubject (emits last value on complete). Example: const clicks = fromEvent(button, 'click').pipe(debounceTime(300), map(e => e.target)); clicks.subscribe(handler). Use for: Event streams, HTTP requests, WebSockets, state management (NgRx, Redux-Observable). Unsubscribe to prevent memory leaks: const sub = obs.subscribe(...); sub.unsubscribe().

99% confidence
A

Cold observables create new producer for each subscriber (unicast), hot observables share single producer among subscribers (multicast). Cold: Each subscription triggers independent execution. Example: const obs = new Observable(subscriber => {subscriber.next(Math.random());}); obs.subscribe(console.log); obs.subscribe(console.log) - prints different values. HTTP requests are cold (each subscribe triggers new request). Hot: Producer exists outside observable, subscribers tap into existing stream. Example: const subject = new Subject(); subject.subscribe(console.log); subject.subscribe(console.log); subject.next(1) - both print 1. DOM events are hot (event fires regardless of subscribers). Convert cold to hot: obs.pipe(share()) or obs.pipe(shareReplay(1)). When to use: Cold for: Data that should be independent per subscriber (HTTP, file reads). Hot for: Shared events (WebSocket, user input, timers). Common mistake: Cold HTTP observable subscribed multiple times = multiple requests. Fix: share() operator. BehaviorSubject and ReplaySubject are hot (store values). Modern pattern (2025): Use share() for hot conversion, shareReplay() to cache last N values for late subscribers.

99% confidence
A

Modern RxJS simplifies exponential backoff with built-in retry config. Pattern: import {retry, timer} from 'rxjs'; observable.pipe(retry({count: 3, delay: (error, retryIndex) => timer(2 ** retryIndex * 1000)})) - retries 3 times with delays: 1s, 2s, 4s. Advanced config: retry({count: 5, delay: (error, retryCount) => {if (error.status === 500) return timer(2 ** retryCount * 1000); throw error;}, resetOnSuccess: true}) - skip non-retryable errors, reset backoff on success. Real-world pattern: const apiCall = http.get(url).pipe(retry({count: 3, delay: (_, retryCount) => {const delay = Math.min(2 ** retryCount * 1000, 30000); console.log(Retry ${retryCount} after ${delay}ms); return timer(delay);}}), catchError(err => of({error: err}))). Benefits: Automatic retry, exponential delay (prevents server overload), max delay cap (30s limit). Use for: HTTP requests (network failures), WebSocket reconnection, polling APIs. 2025 best practice: Combine with tap operator to reset backoff flag when stream emits successfully. Alternative library: backoff-rxjs provides retryBackoff operator with jitter support.

99% confidence
A

RxJS provides multiple error handling operators. catchError: Intercepts error, returns fallback Observable or rethrows custom error. Pattern: obs.pipe(catchError(err => of({error: err.message}))) - returns fallback value, stream continues. Use for: Graceful degradation (show cached data on error). throwError: Creates error Observable. Pattern: catchError(err => throwError(() => new CustomError(err))) - transform error, propagate to subscriber. Use for: Error transformation, logging before rethrow. retry/retryWhen: Resubscribe on error. Pattern: obs.pipe(retry(3)) - retry 3 times. Use for: Transient failures (network issues). finalize: Execute cleanup regardless of completion/error. Pattern: obs.pipe(finalize(() => hideLoader())) - always runs. Use for: Resource cleanup. onErrorResumeNext: Continue with next Observable on error, ignoring error. Use for: Best-effort operations (analytics). Strategy selection: Recoverable error + fallback data available = catchError with of(). Transient error (network) = retry with backoff. Error transformation/logging = catchError + throwError. Always cleanup = finalize. 2024 pattern: Combine catchError + retry: obs.pipe(retry(3), catchError(err => of(defaultValue))).

99% confidence
A

Both encapsulate behavior in separate classes but different intent. Strategy: Selects algorithm, all strategies independent, context chooses strategy (dependency injection). State: Represents different states, states aware of each other (transitions), state changes itself. Example Strategy: SortContext chooses QuickSort or MergeSort, algorithms don't know each other, client picks strategy. Example State: TCPConnection has states (Listen, Established, Closed), states trigger transitions (Established → setState(Closed)), context doesn't control transitions. Key difference: Strategy is static (set once), State is dynamic (changes during execution). Strategy strategies are interchangeable, State states form state machine. Strategy follows Dependency Injection (external control), State follows autonomous transitions (internal control). Both eliminate conditionals but Strategy for algorithm selection, State for state-dependent behavior. Use Strategy for: Configurable algorithms. Use State for: State machines, workflows.

99% confidence
A

Middleware is Chain of Responsibility where each handler can pass control to next. Pattern: type Middleware = (req, res, next) => void; class MiddlewareChain {private middlewares: Middleware[] = []; use(m: Middleware) {this.middlewares.push(m);} execute(req, res) {let index = 0; const next = () => {if (index < this.middlewares.length) this.middlewares[index++](req, res, next);}; next();}}. Usage: const app = new MiddlewareChain(); app.use((req, res, next) => {console.log('Auth'); next();}); app.use((req, res, next) => {console.log('Validation'); next();}); app.execute(req, res). Express.js pattern: app.use(authMiddleware); app.use(validationMiddleware); app.use(businessLogic). Benefits: Composable (mix/match middleware), reusable (auth across routes), testable (isolate middleware). Error handling: try/catch in middleware, call next(error) to skip to error handler. Use for: HTTP request processing, logging, authentication, rate limiting, CORS.

99% confidence
A

Pub/Sub uses message broker between publishers and subscribers (decoupled), Observer has direct subject-observer relationship (coupled). Observer: Subject maintains observer list, notifies directly. Observers know subject (coupled). Example: button.addEventListener (button is subject). Pub/Sub: Publishers publish to topics/channels, broker routes to subscribers. Publishers don't know subscribers (fully decoupled). Example: Redis Pub/Sub, EventBus, message queues. Key difference: Observer is synchronous one-to-many within application, Pub/Sub is async many-to-many often distributed. Observer for: UI events, in-process events, tightly-coupled systems. Pub/Sub for: Microservices communication, cross-application events, scalable event distribution. Implementation: class EventBus {private topics = new Map(); subscribe(topic, handler) {this.topics.get(topic)?.add(handler);} publish(topic, data) {this.topics.get(topic)?.forEach(h => h(data));}}. Libraries: Redis, RabbitMQ, EventEmitter3, mitt.

99% confidence
A

Store executed commands in history stack, implement undo() method on commands. Pattern: interface Command {execute(); undo()}; class History {private undoStack: Command[] = []; private redoStack: Command[] = []; execute(cmd: Command) {cmd.execute(); this.undoStack.push(cmd); this.redoStack = [];} undo() {const cmd = this.undoStack.pop(); if (cmd) {cmd.undo(); this.redoStack.push(cmd);}} redo() {const cmd = this.redoStack.pop(); if (cmd) {cmd.execute(); this.undoStack.push(cmd);}}}. Example: class MoveCommand implements Command {constructor(private obj, private dx, private dy) {} execute() {this.obj.move(this.dx, this.dy);} undo() {this.obj.move(-this.dx, -this.dy);}}. Benefits: Complete history, multiple undo/redo, macro commands (batch operations). Limit stack: keep last N commands (memory management). Use for: Drawing apps, text editors, data modifications, form changes.

99% confidence
A

Null Object provides default 'do nothing' behavior, eliminating null checks. Object with neutral behavior. Use when: (1) Many null checks clutter code, (2) Default behavior is to do nothing, (3) Want to avoid NullPointerException. Pattern: interface Logger {log(msg)}; class ConsoleLogger implements Logger {log(msg) {console.log(msg);}}; class NullLogger implements Logger {log(msg) {/* do nothing */}}. Usage: class Service {constructor(private logger: Logger = new NullLogger()) {} doWork() {this.logger.log('working');}}. Benefits: Eliminates if (logger !== null) checks, polymorphic (same interface), simplifies client code. Trade-offs: Can hide bugs (silent failures), creates extra classes. Alternative: Optional chaining (logger?.log()), default parameters. Use Null Object for: Optional dependencies (logger, metrics), default strategies (no-op validation), placeholder implementations. Modern JavaScript: logger?.log(msg) ?? (() => {})() achieves similar effect.

99% confidence
A

Use EventEmitter for in-process events or message broker for distributed. Pattern: class EventEmitter {private events = new Map<string, Function[]>(); on(event: string, handler: Function) {if (!this.events.has(event)) this.events.set(event, []); this.events.get(event).push(handler);} off(event: string, handler: Function) {const handlers = this.events.get(event); if (handlers) this.events.set(event, handlers.filter(h => h !== handler));} emit(event: string, ...args) {this.events.get(event)?.forEach(h => h(...args));}}. Usage: const emitter = new EventEmitter(); emitter.on('userCreated', (user) => sendEmail(user)); emitter.on('userCreated', (user) => logEvent(user)); emitter.emit('userCreated', newUser). Benefits: Loose coupling, extensibility (add listeners without modifying emitter), async processing. Node.js: EventEmitter built-in. Distributed: Use RabbitMQ, Kafka for cross-service events. Pattern: Domain events (OrderPlaced, PaymentProcessed) with multiple listeners.

99% confidence
A

Event Sourcing persists state as sequence of events instead of current state. Every state change is captured as event (append-only log). Pattern: Store events (OrderCreated, ItemAdded, OrderShipped), reconstruct state by replaying events. Example: class OrderAggregate {private items = []; apply(event) {if (event.type === 'ItemAdded') this.items.push(event.item); if (event.type === 'ItemRemoved') this.items = this.items.filter(i => i.id !== event.itemId);} load(events) {events.forEach(e => this.apply(e));}}. Benefits: (1) Complete audit trail (who/when/what), (2) Time travel (replay to any point), (3) Event replay (rebuild projections), (4) Debugging (reproduce bugs by replaying events). Use when: Need audit compliance, temporal queries (state at specific time), event-driven microservices. Trade-offs: Complexity (event versioning), eventual consistency, storage growth. Modern stack (2024): EventStoreDB or Apache Kafka for event store, CQRS for read models. Use for: Financial systems (transactions), booking systems (reservations), healthcare (patient history). Don't use for: CRUD apps, simple state management.

99% confidence
A

CQRS (Command Query Responsibility Segregation) separates write operations (commands) from read operations (queries). NestJS has built-in @nestjs/cqrs module. Pattern: Commands: class CreateUserCommand {constructor(public name: string, public email: string)}. @CommandHandler(CreateUserCommand) class CreateUserHandler implements ICommandHandler {async execute(cmd: CreateUserCommand) {const user = await this.userRepo.save({name: cmd.name, email: cmd.email}); this.eventBus.publish(new UserCreatedEvent(user.id));}}. Queries: class GetUserQuery {constructor(public id: string)}. @QueryHandler(GetUserQuery) class GetUserHandler implements IQueryHandler {async execute(query: GetUserQuery) {return this.userReadRepo.findById(query.id);}}. Usage: await this.commandBus.execute(new CreateUserCommand('John', '[email protected]')); const user = await this.queryBus.execute(new GetUserQuery(userId)). Benefits: Separate models (write optimized for consistency, read optimized for performance), scalable (scale reads/writes independently), testable (handlers isolated). Combine with Event Sourcing: Commands produce events, queries read projections. 2025 stack: NestJS + EventStoreDB + MongoDB (projections). Use for: High read/write ratio apps, complex domains, microservices.

99% confidence
A

Specification encapsulates business rules as reusable, composable objects. Allows recombining rules using Boolean logic. Use when: (1) Complex validation rules, (2) Need to combine rules dynamically, (3) Want testable, reusable criteria. Pattern: interface Specification {isSatisfiedBy(item: T): boolean; and(other: Specification): Specification; or(other: Specification): Specification; not(): Specification;}. TypeScript implementation: class AgeSpecification implements Specification {constructor(private minAge: number) {} isSatisfiedBy(user: User) {return user.age >= this.minAge;} and(other: Specification) {return new AndSpecification(this, other);}}. Combine: const eligible = new AgeSpecification(18).and(new CountrySpecification('US')).and(new EmailVerifiedSpecification()). Usage: users.filter(u => eligible.isSatisfiedBy(u)). Benefits: (1) Separates business logic from domain models, (2) Composable with AND/OR/NOT, (3) Testable in isolation, (4) Reusable across contexts (validation, selection, authorization), (5) Single Responsibility (one rule per class). 2025 use cases: Form validation (multiple criteria), discount eligibility (age + membership + purchase history), authorization (role + department + clearance), data filtering (search with multiple criteria). Modern TypeScript library: thiagodp/spec-pattern provides matching, filtering, and rule validation. Alternative: Functional approach with predicate functions (const isEligible = (u) => u.age >= 18 && u.country === 'US'). Specification pattern is OOP formalization of predicates with explicit composition. Use Specification when: Rules complex, rules change frequently, need to persist/serialize rules (database queries). Use functions when: Simple predicates, one-time use, functional codebase.

99% confidence
A

Async iterators handle asynchronous data streams with for-await-of loop. Pattern: async function* asyncGenerator() {yield await fetch('/page1').then(r => r.json()); yield await fetch('/page2').then(r => r.json());}. Usage: for await (const data of asyncGenerator()) {console.log(data);}. Real-world paginated API: async function* fetchPages(url) {let page = 1; while (true) {const response = await fetch(${url}?page=${page}); const data = await response.json(); if (data.items.length === 0) break; yield data.items; page++;}}. Usage: for await (const items of fetchPages('/api/users')) {processItems(items);}. Benefits: (1) Lazy loading (fetch only when needed), (2) Memory efficient (don't load all pages), (3) Backpressure handling (consumer controls rate), (4) Clean syntax vs callbacks. Use cases: Paginated APIs, real-time streams (WebSocket, SSE), file processing (line-by-line), database cursors. Modern 2025: Combine with AbortController for cancellation: for await (const item of stream) {if (shouldStop) {controller.abort(); break;}}. Stream transformation: async function* transform(source) {for await (const item of source) yield process(item);}.

99% confidence
A

Generator functions (function*) produce values on-demand using yield. Pattern: function* range(start, end) {for (let i = start; i <= end; i++) yield i;}. Usage: const nums = range(1, 5); console.log(nums.next().value) - prints 1, doesn't compute 2-5 yet. Infinite sequence: function* fibonacci() {let [a, b] = [0, 1]; while (true) {yield a; [a, b] = [b, a + b];}}. Usage: const fib = fibonacci(); console.log(fib.next().value) - 0, console.log(fib.next().value) - 1, can generate forever. Lazy transformation: function* map(iterable, fn) {for (const item of iterable) yield fn(item);}. function* filter(iterable, predicate) {for (const item of iterable) if (predicate(item)) yield item;}. Chain: const nums = range(1, 100); const evens = filter(nums, x => x % 2 === 0); const doubled = map(evens, x => x * 2) - no computation until iteration. Benefits: Memory efficient (don't materialize full collection), lazy (compute on-demand), infinite sequences possible. Use for: Large datasets, pagination, streaming, recursive algorithms (tree traversal). Modern pattern: Combine with async generators for async lazy evaluation.

99% confidence
A

Custom hooks extract component logic into reusable functions, implementing Strategy and Template Method patterns. Pattern: function useAuth() {const [user, setUser] = useState(null); useEffect(() => {const unsubscribe = auth.onAuthStateChanged(setUser); return unsubscribe;}, []); const login = async (email, password) => await auth.signIn(email, password); const logout = async () => await auth.signOut(); return {user, login, logout};}. Usage: const {user, login, logout} = useAuth(). Benefits: (1) Reusable logic across components (DRY), (2) Testable (test hook independently), (3) Composable (combine hooks), (4) Better than HOCs/render props (no wrapper hell). 2024-2025 best practices: Use hooks for: Stateful logic (auth, forms, data fetching), side effects (subscriptions, timers), computed values. Patterns: useData hook (Strategy - swap fetchers), useForm hook (Template Method - validation pipeline), useAsync hook (Command - async operations). Don't use for: Rendering logic (use components), class instance methods (can't use hooks in classes). Modern: Custom hooks primary pattern replacing HOCs and render props. Combine with Context: hook provides data, Context shares across tree.

99% confidence
A

Render props pass function as prop to customize rendering, custom hooks extract logic to reusable function. Render props: component receives render function: <DataProvider render={(data) => } />. Implementation: function DataProvider({render}) {const [data, setData] = useState(null); useEffect(() => {fetch('/api').then(r => r.json()).then(setData);}, []); return render(data);}. Custom hooks: extract logic to function: function useData() {const [data, setData] = useState(null); useEffect(() => {fetch('/api').then(r => r.json()).then(setData);}, []); return data;}. Usage: const data = useData(); return . When to use render props (2024): Dynamic rendering based on data, library API design (React Query uses render props), need access to component instance. When to use custom hooks: Extract stateful logic, reuse across components (primary pattern in 2024), compose multiple hooks. Modern recommendation (2024-2025): Prefer custom hooks for logic, render props for rendering control. Example: React Query: useQuery hook (logic) + render prop API (rendering). Don't use render props for simple logic extraction (use hooks). Both eliminate HOC wrapper hell.

99% confidence
A

EventEmitter is simple publish-subscribe for named events, RxJS Subject is Observable with operators for stream transformation. EventEmitter: Emit named events, subscribe with on(). Pattern: const emitter = new EventEmitter(); emitter.on('data', handler); emitter.emit('data', value). No operators, synchronous by default, Node.js built-in. RxJS Subject: Observable that can emit values, subscribe with subscribe(). Pattern: const subject = new Subject(); subject.subscribe(observer); subject.next(value). Has operators (map, filter, debounce), supports async, error handling, completion. When to use EventEmitter: Simple event notifications (user clicked, file saved), Node.js applications (events core API), no transformation needed, many event types (string keys). When to use RxJS: Need operators (debounce, throttle, merge), async operations (HTTP, WebSocket), error handling important, stream composition (combine multiple sources). Example EventEmitter: server.on('connection', handler) - simple notification. Example RxJS: clicks.pipe(debounceTime(300), map(e => e.target)) - transformation. Memory: Both need cleanup (emitter.off(), subscription.unsubscribe()). Modern 2025: Use EventEmitter for Node.js events, RxJS for frontend reactive programming.

99% confidence
A

Behavioral patterns compose naturally to solve complex problems. Strategy + Observer: Notify when strategy changes. Pattern: class Context {private strategy: Strategy; private observers: Observer[] = []; setStrategy(s: Strategy) {this.strategy = s; this.notifyObservers('strategy-changed', s);}}. Use case: Payment method changed → update UI, validate, log event. Command + Memento: Store state for undo/redo. Pattern: class Command {private memento: Memento; execute() {this.memento = originator.save(); /* do work */} undo() {originator.restore(this.memento);}}. Use case: Text editor - each command saves state before execution. Template Method + Strategy: Skeleton with pluggable steps. Pattern: abstract class Pipeline {process() {this.read(); this.transform(); this.save();} protected abstract transform();}. Concrete: class CSVPipeline extends Pipeline {constructor(private strategy: TransformStrategy) {} transform() {this.strategy.execute();}}. Use case: ETL pipeline with swappable transformation algorithms. State + Command: Commands trigger transitions. Pattern: class State {handle(cmd: Command, context: Context) {cmd.execute(); context.setState(this.nextState(cmd));}}. Use case: Order workflow - PayCommand transitions Draft → Paid → Shipped. Composite + Iterator + Visitor: Traverse tree, apply operations. Pattern: class Tree {accept(visitor: Visitor) {for (const child of this.iterator()) visitor.visit(child);}}. Use case: AST traversal with validation/transformation. 2025 pattern combinations: Hierarchical Observer (distributed systems), MacroCommands with Composite (batch operations), Self-Adaptive Patterns with State (AI-driven state transitions). General principle: Combine when solving orthogonal concerns (don't force). Modern: React hooks enable natural composition (useStrategy + useObserver + useCommand).

99% confidence
A

Choose based on problem type. Strategy: Select algorithm (payment methods). State: State-dependent behavior (TCP states). Command: Encapsulate requests (undo/redo). Observer: Notify dependents of changes (events). Chain of Responsibility: Pass request through handlers (middleware). Template Method: Define algorithm skeleton (data processors). Mediator: Centralize complex interactions (chat room). Visitor: Add operations to structure (AST traversal). Memento: Capture/restore state (snapshots). Iterator: Sequential access (custom collections). Interpreter: Execute language (DSL). Decision tree: Need runtime algorithm selection? Strategy. State machine? State. Event notifications? Observer. Request pipeline? Chain. Undo/transactions? Command. Reusable algorithm structure? Template Method. Multiple unrelated operations on structure? Visitor. Most common: Strategy (algorithm selection), Observer (events), Command (actions), Chain (middleware). Start simple, refactor to pattern when complexity emerges.

99% confidence