Behavioral Complexity: Medium

Command Pattern

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

The Problem

Order operations such as placing, cancelling, and refunding orders require different logic. Without the Command pattern, there is no way to maintain a history, undo a recent action, or queue operations for later execution.

The Solution

The Command pattern wraps each operation in a self-contained command object that implements execute() and undo(). An invoker service manages execution, maintains a stack for undo support, and records a full history log.

Structure

  • Command (interface) — Declares execute() and undo() plus a name identifier.
  • Concrete CommandsPlaceOrderCommand, CancelOrderCommand, RefundOrderCommand.
  • InvokerOrderCommandInvokerService manages execution and undo stack.
  • ClientCommandController maps HTTP actions to commands.

Implementation

Each command tracks execution state to prevent double-execution. The invoker maintains a stack for undo operations and a full history log:

export interface CommandResult {
  success: boolean;
  message: string;
  data?: Record<string, any>;
}

export interface Command {
  readonly name: string;
  execute(): CommandResult;
  undo(): CommandResult;
}

NestJS Integration

The OrderCommandInvokerService is an @Injectable() singleton that persists the command history across requests. Individual command objects are created per request in the controller, keeping them stateful and isolated. The invoker is the only NestJS-managed component; commands are plain classes.

When to Use

  • You need to parameterize objects with operations, queue operations, or schedule their execution.
  • You want to support undo/redo functionality.
  • You need to log all operations for auditing.
  • You want to decouple the object that invokes the operation from the one that performs it.

When NOT to Use

  • The operations are simple and don’t need history, undo, or queuing.
  • Adding command objects for trivial operations introduces unnecessary abstraction.