Command Design Pattern (Behavioral)
Command is a behavioral design pattern that turns a request into a stand-alone object that contains all information about the request. This transformation lets you pass requests as a method arguments, delay or queue a requestβs execution, and support undoable operations.
Problem
Section titled βProblemβImagine youβre creating a new text-editor app. Your current task is to create a toolbar with a bunch of buttons for various operations of the editor. You created a very neat Button class that can be used for buttons on the toolbar, as well as for generic buttons in various dialogs.
While all of these buttons look similar, theyβre all supposed to do different things. The simplest solution would be to create tons of subclasses for each place where the button is used. These subclasses would contain the code for executing a click.
Before long, you realize that this approach is deeply flawed. First, you have an enormous number of subclasses. Second, the Button class would depend on classes that it shouldnβt even know about, like the Editor class.
Solution
Section titled βSolutionβGood software design is often based on the principle of separation of concerns, which usually results in breaking an app into layers. The Command pattern suggests that GUI objects shouldnβt send these requests directly. Instead, you should extract all of the request details, such as the object being called, the name of the method and the list of arguments into a separate command class with a single method that triggers this request.
Command objects serve as links between various GUI and business logic objects. From now on, the GUI object doesnβt need to know what business logic object will receive the request and how itβll be processed.
Real-World Analogy
Section titled βReal-World AnalogyβAfter a long walk in the city, you go to a nice restaurant and sit at the table. A waiter comes up to you and takes your order, writing it down on a piece of paper. The waiter goes to the kitchen and sticks the order on the wall. After a while, the order gets to the chef, who reads it and cooks the meal.
The paper order serves as a command. It remains in a queue until the chef is ready to serve it. The order contains all the relevant information required to cook the meal. It allows the chef to start cooking right away instead of running around trying to clarify the order details directly from you.
Structure
Section titled βStructureβ- Sender (Invoker) class is responsible for initiating requests. This class must have a field for storing a reference to a command object.
- Command interface usually declares just a single method for executing the command.
- Concrete Commands implement various kinds of requests. A concrete command isnβt supposed to perform the work on its own, but rather pass the call to one of the business logic objects.
- Receiver class contains some business logic. Almost any object may act as a receiver.
- Client creates and configures concrete command objects. The client must pass all of the request parameters, including a receiver instance, into the commandβs constructor.
Structure (Class Diagram)
Section titled βStructure (Class Diagram)βclassDiagram
class Invoker {
-command: Command
+setCommand(command: Command)
+executeCommand()
}
class Command {
<<interface>>
+execute()
}
class ConcreteCommand {
-receiver: Receiver
-params
+ConcreteCommand(receiver, params)
+execute()
}
class Receiver {
+operation(a, b, c)
}
Invoker o-- Command
Command <|-- ConcreteCommand
ConcreteCommand --> Receiver
Client ..> ConcreteCommand
Client ..> Invoker
Pseudocode
Section titled βPseudocodeβ# The base command class defines the basic interface for all# concrete commands.abstract class Command: protected field app: Application protected field editor: Editor protected field backup: string
constructor Command(app, editor): this.app = app this.editor = editor
# Make a backup of the editor's state. method saveBackup(): backup = editor.text
# Restore the editor's state. method undo(): editor.text = backup
# The execution method is declared abstract to force all # concrete commands to provide their own implementations. abstract method execute()
# The concrete commands delegate the work to the receiver.class CopyCommand extends Command: method execute(): app.clipboard = editor.getSelection() return false
class PasteCommand extends Command: method execute(): saveBackup() editor.replaceSelection(app.clipboard) return trueApplicability
Section titled βApplicabilityβ- Parameterize Objects with Operations: Use the Command pattern when you want to parameterize objects with operations.
- Queue/Schedule Operations: Use the pattern when you want to queue operations, schedule their execution, or execute them remotely.
- Reversible Operations: Use the pattern when you need to implement reversible operations (Undo/Redo).
How to Implement
Section titled βHow to Implementβ- Declare the command interface with a single execution method.
- Extract requests into concrete command classes that implement the command interface.
- Identify classes that will act as invokers. Add fields for storing commands to these classes.
- Change the invokers so that they execute the command instead of sending a request to the receiver directly.
- The client must initialize objects in the following order: create receivers, create commands (associating them with receivers), create invokers (associating them with commands).
Pros and Cons
Section titled βPros and ConsβPros:
- Single Responsibility Principle: You can decouple classes that invoke operations from classes that perform these operations.
- Open/Closed Principle: You can introduce new commands into the app without breaking existing client code.
- You can implement undo/redo.
- You can implement deferred execution of operations.
- You can assemble a set of simple commands into a complex one.
Cons:
- The code may become more complicated since youβre introducing a whole new layer between senders and receivers.
Relations with other Design Patterns
Section titled βRelations with other Design Patternsβ- Chain of Responsibility, Command, Mediator, and Observer address various ways of connecting senders and receivers of requests.
- Handlers in Chain of Responsibility can be implemented as Commands.
- Command and Memento can be used together when implementing βundoβ.
- Command and Strategy may look similar because you can use both to parameterize an object with some action. However, they have very different intents.
Code Examples
Section titled βCode ExamplesβCode Examples (C#)
Section titled βCode Examples (C#)β// Commandpublic interface ICommand{ void Execute();}
// Receiverpublic class Light{ public void TurnOn() => Console.WriteLine("Light on"); public void TurnOff() => Console.WriteLine("Light off");}
// Concrete Commandspublic class TurnOnCommand : ICommand{ private readonly Light _light;
public TurnOnCommand(Light light) { _light = light; }
public void Execute() => _light.TurnOn();}
public class TurnOffCommand : ICommand{ private readonly Light _light;
public TurnOffCommand(Light light) { _light = light; }
public void Execute() => _light.TurnOff();}
// Invokerpublic class RemoteControl{ private ICommand _command;
public void SetCommand(ICommand command) { _command = command; }
public void PressButton() { _command.Execute(); }}
// Usageclass Program{ static void Main() { var light = new Light(); var remote = new RemoteControl();
remote.SetCommand(new TurnOnCommand(light)); remote.PressButton();
remote.SetCommand(new TurnOffCommand(light)); remote.PressButton(); }}Code Examples (Python)
Section titled βCode Examples (Python)βfrom __future__ import annotationsfrom abc import ABC, abstractmethod
class Command(ABC): """ The Command interface declares a method for executing a command. """ @abstractmethod def execute(self) -> None: pass
class SimpleCommand(Command): """ Some commands can implement simple operations on their own. """ def __init__(self, payload: str) -> None: self._payload = payload
def execute(self) -> None: print(f"SimpleCommand: See, I can do simple things like printing" f"({self._payload})")
class ComplexCommand(Command): """ However, some commands can delegate more complex operations to other objects, called "receivers." """ def __init__(self, receiver: Receiver, a: str, b: str) -> None: self._receiver = receiver self._a = a self._b = b
def execute(self) -> None: print("ComplexCommand: Complex stuff should be done by a receiver object", end="") self._receiver.do_something(self._a) self._receiver.do_something_else(self._b)
class Receiver: """ The Receiver classes contain some important business logic. """ def do_something(self, a: str) -> None: print(f"\nReceiver: Working on ({a}.)", end="")
def do_something_else(self, b: str) -> None: print(f"\nReceiver: Also working on ({b}.)", end="")
class Invoker: """ The Invoker is associated with one or several commands. It sends a request to the command. """ _on_start = None _on_finish = None
def set_on_start(self, command: Command): self._on_start = command
def set_on_finish(self, command: Command): self._on_finish = command
def do_something_important(self) -> None: print("Invoker: Does anybody want something done before I begin?") if isinstance(self._on_start, Command): self._on_start.execute()
print("Invoker: ...doing something really important...")
print("Invoker: Does anybody want something done after I finish?") if isinstance(self._on_finish, Command): self._on_finish.execute()
if __name__ == "__main__": invoker = Invoker() invoker.set_on_start(SimpleCommand("Say Hi!")) receiver = Receiver() invoker.set_on_finish(ComplexCommand(receiver, "Send email", "Save report"))
invoker.do_something_important()Code Examples (C++)
Section titled βCode Examples (C++)β#include <iostream>#include <memory>
// Commandclass ICommand {public: virtual ~ICommand() = default; virtual void Execute() = 0;};
// Receiverclass Light {public: void TurnOn() { std::cout << "Light on" << std::endl; }
void TurnOff() { std::cout << "Light off" << std::endl; }};
// Concrete Commandsclass TurnOnCommand : public ICommand {private: Light& light;
public: TurnOnCommand(Light& l) : light(l) {}
void Execute() override { light.TurnOn(); }};
class TurnOffCommand : public ICommand {private: Light& light;
public: TurnOffCommand(Light& l) : light(l) {}
void Execute() override { light.TurnOff(); }};
// Invokerclass RemoteControl {private: std::unique_ptr<ICommand> command;
public: void SetCommand(std::unique_ptr<ICommand> cmd) { command = std::move(cmd); }
void PressButton() { command->Execute(); }};
// Usageint main() { Light light; RemoteControl remote;
remote.SetCommand(std::make_unique<TurnOnCommand>(light)); remote.PressButton();
remote.SetCommand(std::make_unique<TurnOffCommand>(light)); remote.PressButton();
return 0;}Code Examples (Java)
Section titled βCode Examples (Java)β// Commandpublic interface ICommand { void execute();}
// Receiverpublic class Light {
public void turnOn() { System.out.println("Light on"); }
public void turnOff() { System.out.println("Light off"); }}
// Concrete Commandspublic class TurnOnCommand implements ICommand {
private final Light light;
public TurnOnCommand(Light light) { this.light = light; }
@Override public void execute() { light.turnOn(); }}
public class TurnOffCommand implements ICommand {
private final Light light;
public TurnOffCommand(Light light) { this.light = light; }
@Override public void execute() { light.turnOff(); }}
// Invokerpublic class RemoteControl {
private ICommand command;
public void setCommand(ICommand command) { this.command = command; }
public void pressButton() { command.execute(); }}
// Usagepublic class Program { public static void main(String[] args) { Light light = new Light(); RemoteControl remote = new RemoteControl();
remote.setCommand(new TurnOnCommand(light)); remote.pressButton();
remote.setCommand(new TurnOffCommand(light)); remote.pressButton(); }}Code Examples (JavaScript)
Section titled βCode Examples (JavaScript)β// Command (simulated interface)class ICommand { execute() { throw new Error("execute() must be implemented"); }}
// Receiverclass Light { turnOn() { console.log("Light on"); }
turnOff() { console.log("Light off"); }}
// Concrete Commandsclass TurnOnCommand extends ICommand { constructor(light) { super(); this.light = light; }
execute() { this.light.turnOn(); }}
class TurnOffCommand extends ICommand { constructor(light) { super(); this.light = light; }
execute() { this.light.turnOff(); }}
// Invokerclass RemoteControl { setCommand(command) { this.command = command; }
pressButton() { this.command.execute(); }}
// Usageconst light = new Light();const remote = new RemoteControl();
remote.setCommand(new TurnOnCommand(light));remote.pressButton();
remote.setCommand(new TurnOffCommand(light));remote.pressButton();Code Examples (Visual Basic)
Section titled βCode Examples (Visual Basic)β' ============================' Command' ============================Public Interface ICommand Sub Execute()End Interface
' ============================' Receiver' ============================Public Class Light Public Sub TurnOn() Console.WriteLine("Light on") End Sub
Public Sub TurnOff() Console.WriteLine("Light off") End SubEnd Class
' ============================' Concrete Commands' ============================Public Class TurnOnCommand Implements ICommand
Private ReadOnly _light As Light
Public Sub New(light As Light) _light = light End Sub
Public Sub Execute() Implements ICommand.Execute _light.TurnOn() End SubEnd Class
Public Class TurnOffCommand Implements ICommand
Private ReadOnly _light As Light
Public Sub New(light As Light) _light = light End Sub
Public Sub Execute() Implements ICommand.Execute _light.TurnOff() End SubEnd Class
' ============================' Invoker' ============================Public Class RemoteControl Private _command As ICommand
Public Sub SetCommand(command As ICommand) _command = command End Sub
Public Sub PressButton() _command.Execute() End SubEnd Class
' ============================' Usage' ============================Module Program Sub Main() Dim light As New Light() Dim remote As New RemoteControl()
remote.SetCommand(New TurnOnCommand(light)) remote.PressButton()
remote.SetCommand(New TurnOffCommand(light)) remote.PressButton() End SubEnd ModuleCode Examples (Rust)
Section titled βCode Examples (Rust)β// Commandtrait Command { fn execute(&self);}
// Receiverstruct Light;
impl Light { fn turn_on(&self) { println!("Light on"); }
fn turn_off(&self) { println!("Light off"); }}
// Concrete Commandsstruct TurnOnCommand { light: Light,}
impl TurnOnCommand { fn new(light: Light) -> Self { Self { light } }}
impl Command for TurnOnCommand { fn execute(&self) { self.light.turn_on(); }}
struct TurnOffCommand { light: Light,}
impl TurnOffCommand { fn new(light: Light) -> Self { Self { light } }}
impl Command for TurnOffCommand { fn execute(&self) { self.light.turn_off(); }}
// Invokerstruct RemoteControl { command: Option<Box<dyn Command>>,}
impl RemoteControl { fn new() -> Self { Self { command: None } }
fn set_command(&mut self, command: Box<dyn Command>) { self.command = Some(command); }
fn press_button(&self) { if let Some(cmd) = &self.command { cmd.execute(); } }}
// Usagefn main() { let light = Light; let mut remote = RemoteControl::new();
remote.set_command(Box::new(TurnOnCommand::new(light))); remote.press_button();
let light = Light; remote.set_command(Box::new(TurnOffCommand::new(light))); remote.press_button();}Code Examples (PHP)
Section titled βCode Examples (PHP)β<?php
// Commandinterface ICommand{ public function execute(): void;}
// Receiverclass Light{ public function turnOn(): void { echo "Light on\n"; }
public function turnOff(): void { echo "Light off\n"; }}
// Concrete Commandsclass TurnOnCommand implements ICommand{ private Light $light;
public function __construct(Light $light) { $this->light = $light; }
public function execute(): void { $this->light->turnOn(); }}
class TurnOffCommand implements ICommand{ private Light $light;
public function __construct(Light $light) { $this->light = $light; }
public function execute(): void { $this->light->turnOff(); }}
// Invokerclass RemoteControl{ private ICommand $command;
public function setCommand(ICommand $command): void { $this->command = $command; }
public function pressButton(): void { $this->command->execute(); }}
// Usage$light = new Light();$remote = new RemoteControl();
$remote->setCommand(new TurnOnCommand($light));$remote->pressButton();
$remote->setCommand(new TurnOffCommand($light));$remote->pressButton();Code Examples (Go)
Section titled βCode Examples (Go)βpackage main
import ( "fmt")
// Commandtype Command interface { Execute()}
// Receivertype Light struct{}
func (Light) TurnOn() { fmt.Println("Light on")}
func (Light) TurnOff() { fmt.Println("Light off")}
// Concrete Commandstype TurnOnCommand struct { light *Light}
func NewTurnOnCommand(light *Light) *TurnOnCommand { return &TurnOnCommand{light: light}}
func (c *TurnOnCommand) Execute() { c.light.TurnOn()}
type TurnOffCommand struct { light *Light}
func NewTurnOffCommand(light *Light) *TurnOffCommand { return &TurnOffCommand{light: light}}
func (c *TurnOffCommand) Execute() { c.light.TurnOff()}
// Invokertype RemoteControl struct { command Command}
func (r *RemoteControl) SetCommand(cmd Command) { r.command = cmd}
func (r *RemoteControl) PressButton() { r.command.Execute()}
// Usagefunc main() { light := &Light{} remote := &RemoteControl{}
remote.SetCommand(NewTurnOnCommand(light)) remote.PressButton()
remote.SetCommand(NewTurnOffCommand(light)) remote.PressButton()}Code Examples (Ruby)
Section titled βCode Examples (Ruby)β# Commandclass Commanddef execute raise NotImplementedError, "Subclasses must implement execute"endend
# Receiverclass Lightdef turn_on puts "Light on"end
def turn_off puts "Light off"endend
# Concrete Commandsclass TurnOnCommand < Commanddef initialize(light) @light = lightend
def execute @light.turn_onendend
class TurnOffCommand < Commanddef initialize(light) @light = lightend
def execute @light.turn_offendend
# Invokerclass RemoteControldef set_command(command) @command = commandend
def press_button @command.executeendend
# Usagelight = Light.newremote = RemoteControl.new
remote.set_command(TurnOnCommand.new(light))remote.press_button
remote.set_command(TurnOffCommand.new(light))remote.press_buttonCode Examples (Perl)
Section titled βCode Examples (Perl)β#!/usr/bin/perluse strict;use warnings;
############################# Command (Interface-like)############################package Command;
sub execute { die "execute() must be implemented by subclass";}
############################# Receiver############################package Light;
sub new { bless {}, shift }
sub turn_on { print "Light on\n"; }sub turn_off { print "Light off\n"; }
############################# Concrete Commands############################package TurnOnCommand;our @ISA = ('Command');
sub new { my ($class, $light) = @_; return bless { light => $light }, $class;}
sub execute { my ($self) = @_; $self->{light}->turn_on();}
package TurnOffCommand;our @ISA = ('Command');
sub new { my ($class, $light) = @_; return bless { light => $light }, $class;}
sub execute { my ($self) = @_; $self->{light}->turn_off();}
############################# Invoker############################package RemoteControl;
sub new { bless { command => undef }, shift }
sub set_command { my ($self, $command) = @_; $self->{command} = $command;}
sub press_button { my ($self) = @_; $self->{command}->execute();}
############################# Usage############################package main;
my $light = Light->new();my $remote = RemoteControl->new();
$remote->set_command(TurnOnCommand->new($light));$remote->press_button();
$remote->set_command(TurnOffCommand->new($light));$remote->press_button();Code Examples (TypeScript)
Section titled βCode Examples (TypeScript)β// Commandinterface ICommand { execute(): void;}
// Receiverclass Light { turnOn(): void { console.log("Light on"); }
turnOff(): void { console.log("Light off"); }}
// Concrete Commandsclass TurnOnCommand implements ICommand { private light: Light;
constructor(light: Light) { this.light = light; }
execute(): void { this.light.turnOn(); }}
class TurnOffCommand implements ICommand { private light: Light;
constructor(light: Light) { this.light = light; }
execute(): void { this.light.turnOff(); }}
// Invokerclass RemoteControl { private command: ICommand;
setCommand(command: ICommand): void { this.command = command; }
pressButton(): void { this.command.execute(); }}
// Usageconst light = new Light();const remote = new RemoteControl();
remote.setCommand(new TurnOnCommand(light));remote.pressButton();
remote.setCommand(new TurnOffCommand(light));remote.pressButton();