Command Pattern
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
Intent & Objective
Turn a request into a stand-alone object containing all information about the request. This transformation lets you pass requests as method arguments, delay or queue a request’s execution, and support reversible undo operations.
"You tell the waiter what you want. They write down a ticket and pin it to the kitchen queue board, encapsulated to be executed by the cooks later."
"A general issues a sealed command envelope to be delivered, scheduled, and executed at a specific operational hour."
"You give a command ('turn off bedroom lights'); the assistant encapsulates it as an action payload and executes it."
"Each commit encapsulates a specific change request that can be queued, reviewed, and executed later via a merge or cherry-pick."
The Problem
Directly hardcoding UI buttons to business actions: having `SaveButton` invoke `Document.save()`, `PrintButton` invoke `Printer.print()`. The GUI becomes tightly coupled to backend services, making undo/redo, command macros, and queuing impossible.
The Solution
Separate GUI controls from business actions by introducing Command objects with an `execute()` and `undo()` method. Invokers simply trigger `command.execute()`.
Key Participants & Architectural Roles
Code Samples (Traditional OOP vs Functional Programming)
Available in C++, Python, and JavaParadigm Contrast: Traditional OOP vs Functional / Data-Oriented
In OOP, Command is an object containing `execute()` and `undo()`. In Functional Programming, a Command is a closure, thunk, or IO action: a zero-argument function `() -> Result` packaged with its captured parameters.
Advantages
- ✓ Single Responsibility Principle: decouples classes that invoke operations from classes that perform them
- ✓ Open/Closed Principle: introduces new commands without breaking existing client code
- ✓ Enables undo/redo history stacks, macros, and job queuing
Trade-offs
- ✗ Code may become more complicated since you are introducing a whole new layer between senders and receivers
When to Apply
- → When you want to parameterize UI elements with operations
- → When you want to queue operations, schedule their execution, or execute them remotely
- → When you need to implement reversible operations (Undo/Redo)
When to Avoid
- ! For direct synchronous method calls that will never need queuing, logging, or undo