Command Pattern
Encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations. Command turns method calls into standalone objects that contain all the information needed to perform an action.
✦ Problem
You need to issue requests to objects without knowing anything about the operation being requested or the receiver. You also want to support undo/redo, queuing operations, scheduling execution, or logging command history. Directly coupling the sender to the receiver's methods makes all of these capabilities difficult to implement.
✦ Solution
Create a command interface with an execute method. Each concrete command stores the receiver and the parameters needed for the action. The sender (invoker) triggers the command without knowing what it does. Commands can be stored in a history stack for undo/redo, serialized for logging, or queued for deferred execution.
Participants
| Role | Responsibility |
|---|---|
| Command | Declares an interface for executing an operation |
| ConcreteCommand | Binds a Receiver to an action; implements execute by invoking operations on the Receiver |
| Invoker | Asks the command to carry out the request |
| Receiver | Knows how to perform the operations; any class can serve as a receiver |
TypeScript Example
interface Command {
execute(): void;
undo(): void;
description: string;
}
class TextEditor {
content = "";
insert(text: string, pos: number) {
this.content = this.content.slice(0, pos) + text + this.content.slice(pos);
}
delete(pos: number, length: number): string {
const deleted = this.content.slice(pos, pos + length);
this.content = this.content.slice(0, pos) + this.content.slice(pos + length);
return deleted;
}
}
class InsertCommand implements Command {
description: string;
constructor(private editor: TextEditor, private text: string, private pos: number) {
this.description = `Insert "${text}" at ${pos}`;
}
execute() { this.editor.insert(this.text, this.pos); }
undo() { this.editor.delete(this.pos, this.text.length); }
}
class CommandHistory {
private history: Command[] = [];
execute(cmd: Command) {
cmd.execute();
this.history.push(cmd);
}
undo(): string | undefined {
const cmd = this.history.pop();
if (cmd) { cmd.undo(); return cmd.description; }
}
}
const editor = new TextEditor();
const history = new CommandHistory();
history.execute(new InsertCommand(editor, "Hello", 0));
history.execute(new InsertCommand(editor, " World", 5));
console.log(editor.content); // "Hello World"
history.undo();
console.log(editor.content); // "Hello"Real-World Example
Text editors universally use the Command pattern for undo/redo—each keystroke, formatting change, or paste operation is a command object stored in a history stack. Database transactions wrap SQL statements as commands. Task queues like BullMQ or Celery serialize commands for later execution. GUI buttons map user actions to command objects, decoupling the UI from the business logic.
✓ When to Use
- •You need to parameterize objects with actions to perform
- •You want to queue, schedule, or execute operations at different times
- •You need to support undo/redo functionality
- •You want to structure a system around high-level operations built from primitive operations (transactions)
✗ When Not to Use
- •The operations are simple and don't require undo, queuing, or logging
- •Creating a command object for every trivial operation adds unnecessary complexity
- •The system has strict real-time requirements and the overhead of command objects matters
Understanding the Command Pattern
The Command pattern is one of the most important behavioral design patterns in object-oriented software design. Originally cataloged by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides) in their seminal 1994 book "Design Patterns: Elements of Reusable Object-Oriented Software," this pattern continues to be a cornerstone of modern software architecture.
Encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations. Command turns method calls into standalone objects that contain all the information needed to perform an action. The pattern involves the following key participants: Command, ConcreteCommand, Invoker, Receiver. Each participant has a well-defined role, and the interactions between them create a flexible, maintainable structure that can evolve with changing requirements.
In TypeScript and modern JavaScript development, the Command pattern is particularly valuable because the language's type system and interface support allow you to express the pattern with compile-time safety. TypeScript generics can make Command implementations even more flexible and reusable while maintaining strong type checking throughout the pattern's structure.
Knowing when to apply the Command pattern is as important as knowing how. Common use cases include: You need to parameterize objects with actions to perform; You want to queue, schedule, or execute operations at different times; You need to support undo/redo functionality. However, overusing design patterns can lead to unnecessarily complex code. Always evaluate whether the pattern genuinely solves your problem or if a simpler approach would suffice.
The Command pattern is related to several other design patterns: Memento, Observer, Strategy, Chain of Responsibility, Visitor. Understanding these relationships helps you choose the right pattern for your specific situation and combine patterns effectively when building complex systems.
Related Patterns
Captures and externalizes an object's internal state so it can be restored later, without violating encapsulation. Memen…
Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified …
Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary …
Passes a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next…
Represents an operation to be performed on elements of an object structure. Visitor lets you define new operations witho…
More Behavioral Patterns
Explore All Design Patterns
Browse our complete reference of 23 design patterns with TypeScript examples, UML participants, and practical guidance.