Behavioral Pattern
Command
Encapsulate a request as an object, letting you parameterize clients with different requests, queue or log them, and support undoable operations.
An action as an object.
The Command pattern turns an action into a standalone object. Instead of calling a method directly, you create a command object that knows how to perform the action, then hand it to something that runs it later. Think of a restaurant order slip: it captures a request that can be queued, passed around, and fulfilled.
bad.py
# Problem: UI buttons call receivers directly — no undo, no queue. class Editor: def paste(self, text): self.doc += text def delete(self, n): self.doc = self.doc[:-n] # toolbar_paste_btn -> editor.paste(...) tightly coupled # Can't log, retry, or undo a "paste" as a first-class action.
good.py
# Fix: Command — an action object with execute (and optional undo). class PasteCommand: def __init__(self, editor, text): self.editor, self.text = editor, text def execute(self): self.editor.paste(self.text) def undo(self): self.editor.delete(len(self.text)) class Button: def __init__(self, command): self.command = command # invoker knows Command, not Editor def click(self): self.command.execute() history = [] cmd = PasteCommand(editor, "hi") Button(cmd).click() history.append(cmd) history[-1].undo() # commands enable undo stacks
Decoupling invoker from receiver.
Participants: a Command interface (usually with execute()),
ConcreteCommands that bind an action to a Receiver, an
Invoker that triggers commands, and the Client that creates and
configures them.
- Undo/redo — add an
undo()method; keep a history stack of executed commands. - Queuing & scheduling — commands can be stored, delayed, or run on worker threads.
- Logging & replay — persist commands to re-run after a crash.
Applications and relations.
- Macro commands — a composite command runs a sequence of sub-commands (combines with the Composite pattern).
- vs Strategy — both wrap behavior in an object, but Command represents a request/action (often with undo, receiver, queuing), while Strategy represents an interchangeable algorithm.
- Real uses — GUI buttons/menu items, task queues and thread pools
(
Runnableis essentially a command), transactional operations, and CQRS/event-sourcing where commands capture intent. - Cost — a class per action can proliferate; lambdas/functions often make lightweight commands.