Command
Command is a pattern that turns a request -- 'do this' -- into a standalone object. The side sending the request (Invoker) does not know what the request specifically does or how, and the side performing the work (Receiver) does not know who requested it. Once a request becomes an object, it can be stored, transmitted, undone, and replayed.
βΆArchitecture Diagram
π ProcessDashed line animations indicate the flow direction of data or requests
Consider building a GUI where pressing a button triggers an action. If the action is coded directly inside the button, duplicating the same action for a menu, keyboard shortcut, or context menu means duplicating the code. When an 'undo' feature is needed, the problem grows: you must remember what action ran when, and also hold a way to reverse it. If actions are scattered as function calls, there is no object to serve as a history record.
Early GUI and job-processing systems needed to reuse the same action from multiple entry points such as buttons, menus, shortcuts, and queues. But when actions were scattered as raw function calls, there was no stable unit to store, replay later, or undo. The pressure was to treat the request itself like data: something that could be queued, recorded, retried, and reversed. Command emerged from that pressure. It later expanded into message queues and scheduling systems, but its starting point is moving a request's lifecycle outside the immediate method call.
Command has four roles. The Command interface defines execute(). A Concrete Command implements that interface, holding a Receiver reference and the parameters needed for execution. The Invoker receives and stores a Command object, calling execute() at the appropriate moment. The Receiver performs the actual business logic. The flow works like this: the Client creates a Receiver, creates a Command containing that Receiver, and registers it with the Invoker. The Invoker fires execute() on a trigger (button click, schedule, event), and the Command delegates the real work to its internal Receiver. To support undo, an undo() method is added to the Command, and the Invoker pushes executed Commands onto a stack. On an undo request, the top Command is popped and undo() is called. This structure makes extensions like execution-history management, macros (bundling multiple Commands into one), and transactions (execute all or undo all) straightforward.
Command and Strategy both wrap behavior in objects, but the intent differs. Strategy is about 'performing the same task in a different way' by swapping algorithms; Command is about 'recording what was done and controlling it' by objectifying requests. Strategy cares about algorithm replacement; Command cares about execution timing, history, and undo. Confusion with Observer is also possible. Observer propagates a state change to multiple recipients, while Command turns a single request into an object and manages its lifecycle (creation, delivery, execution, undo). They are often used together in event systems: Observer propagates the event, and inside a handler a Command object is executed.
Command's most compelling use case is undo/redo. In text editors, graphic editors, and spreadsheets, recording every user operation as a Command means undo is implemented simply by rewinding the stack. It is also valuable for job queues. Serializing requests into Command objects lets them be sent across the network to another server or queued for a worker to process later. When transaction boundaries are needed, multiple Commands are bundled: all execute() or, if any fails, all undo(). The signals for adoption are 'this action must be reversible,' 'this request must be executed later,' or 'action history must be recorded.' If a simple method call suffices and neither history nor undo is needed, there is no reason to introduce Command.