What is the Command Design Pattern?

Göksu Deniz
8 min readDec 14, 2022

--

Image is created by DALL-E 2 AI

The command design pattern is a behavioral design pattern that is used to encapsulate a request as an object. This allows for a separation of concerns between the object that invokes the command and the object that knows how to execute it. This can be useful in a variety of situations, such as implementing undo/redo functionality, or allowing for different implementations of a command to be used interchangeably. It can also make it easier to create and manage instances of commands, as well as allowing for the creation of composite commands that can be treated as a single unit.

The command design pattern is a useful way to implement undo and redo functionality in an application. It allows you to separate the object that invokes an operation from the object that performs the operation. This makes it easier to add new types of operations and to manage the history of operations. It also makes it easier to implement undo and redo functionality, because you can simply store the commands that have been executed and replay them in reverse order to undo an operation, or replay them in the original order to redo an operation. This can be useful in many different types of applications, such as drawing programs, word processors, and video game editors.

What did the command object say to the client that was using it? “I’m here to take your requests, not to make your decisions for you.”

A command design pattern is a way for us to separate the thing we want to do from the code that actually does it. Imagine you’re playing a game with your friends and you want to make a robot character move forward. The robot character has a bunch of different parts, like wheels and motors, that all have to work together to make the robot move.

The command design pattern is like giving the robot a remote control. The remote control has a button that says “move forward” and when you press it, the robot character will move forward. But the important thing is that the button on the remote control doesn’t actually make the robot move — it just sends a command to the robot telling it what to do. The robot then uses its own code to figure out how to make its wheels and motors move in the right way to make it go forward.

This is useful because it means that you can change how the robot moves without changing the remote control. For example, you could make the robot move faster or slower, or make it turn left or right, without having to change the remote control at all. And because the remote control is separate from the robot’s code, you can use the same remote control to control different robots, each with their own unique way of moving.

So the command design pattern is a way to make it easier to give instructions to things without worrying about how they actually do what you want them to do. It’s like telling someone what to do without worrying about how they’re going to do it — you just give them the command and they figure out the details.

using System;
using System.Collections.Generic;

namespace CommandPatternExample
{
// The Command interface
interface ICommand
{
void Execute();
}

// The Invoker class
class Switch
{
private List<ICommand> commands = new List<ICommand>();

public void StoreAndExecute(ICommand command)
{
commands.Add(command);
command.Execute();
}
}

// The Receiver class
class Light
{
public void TurnOn()
{
Console.WriteLine("The light is on");
}

public void TurnOff()
{
Console.WriteLine("The light is off");
}
}

// The Command for turning on the light - ConcreteCommand #1
class FlipUpCommand : ICommand
{
private Light light;

public FlipUpCommand(Light light)
{
this.light = light;
}

public void Execute()
{
light.TurnOn();
}
}

// The Command for turning off the light - ConcreteCommand #2
class FlipDownCommand : ICommand
{
private Light light;

public FlipDownCommand(Light light)
{
this.light = light;
}

public void Execute()
{
light.TurnOff();
}
}

class Program
{
static void Main(string[] args)
{
Light lamp = new Light();

ICommand switchUp = new FlipUpCommand(lamp);
ICommand switchDown = new FlipDownCommand(lamp);

Switch s = new Switch();

// Invoking the switchOn() method on switchUp
s.StoreAndExecute(switchUp);

// Invoking the switchOff() method on switchDown
s.StoreAndExecute(switchDown);

// You could continue the code by adding additional commands and executing them using the Switch class,
// for example:
ICommand switchDim = new DimCommand(lamp);
s.StoreAndExecute(switchDim);

// Or you could add a new Receiver class and create commands for it:
Fan fan = new Fan();
ICommand fanOn = new FanOnCommand(fan);
ICommand fanOff = new FanOffCommand(fan);

s.StoreAndExecute(fanOn);
s.StoreAndExecute(fanOff);
}
}

To undo an operation, you can add a new Undo method to the ICommand interface, which will be called by the Switch class to undo the last operation. You can implement this by adding a stack to the Switch class, which will store the executed commands. The Undo method can then pop the last command off the stack and execute its own undo operation.

// The Command interface
interface ICommand
{
void Execute();
void Undo();
}


// The Invoker class
class Switch
{
// converted to Stack from List because of using Pop method.
private Stack<ICommand> commands = new Stack<ICommand>();

public void StoreAndExecute(ICommand command)
{
commands.Push(command);
command.Execute();
}

public void UndoLast()
{
if (commands.Count > 0)
{
// pop is the method of Stack class
// which return the last object and remove it from the list.
ICommand command = commands.Pop();
command.Undo();
}
}
}

Then you can add Undo methods to ICommand concretes.


// The Command for turning on the light - ConcreteCommand #1
class FlipUpCommand : ICommand
{
private Light light;

public FlipUpCommand(Light light)
{
this.light = light;
}

public void Execute()
{
light.TurnOn();
}

public void Undo()
{
light.TurnOff();
}
}

/ The Command for turning off the light - ConcreteCommand #2
class FlipDownCommand : ICommand
{
private Light light;
public FlipDownCommand(Light light)
{
this.light = light;
}

public void Execute()
{
light.TurnOff();
}

public void Undo()
{
light.TurnOn();
}
}

Now, you can free to undo last operation.

ICommand flipUp = new FlipUpCommand(light);
ICommand flipDown = new FlipDownCommand(light);

lightSwitch.StoreAndExecute(flipUp);
lightSwitch.StoreAndExecute(flipDown);

lightSwitch.UndoLast();
lightSwitch.UndoLast();

What did the command object say to the client when it was asked to perform an operation? “I’m just following orders.”

One common use case for the Command design pattern is to implement undo/redo functionality in an application. By encapsulating each action as a command object, it is easy to maintain a history of operations and allow the user to undo and redo actions. This can be particularly useful in applications that involve complex or irreversible actions, such as financial transactions or document editing.

Another use case for the Command design pattern is to implement deferred execution of operations. In some scenarios, the cost of creating a command object may be high, and it may not always be necessary to execute the operation. By encapsulating the operation as a command object, it is possible to delay the execution until it is needed, which can help to improve the performance and efficiency of the application.

The Command design pattern can also be used to implement macros, which are sequences of related actions that can be treated as a single unit and executed with a single command. This can be useful for automating repetitive tasks or for creating complex operations that involve multiple steps.

UML Diagram

Created on stackedit.io

In this diagram, the Command class defines an interface for executing an action, and the ConcreteCommand classes implement this interface to execute the action on a Receiver object. The Invoker class holds a Command object and invokes the command's execute method.

Conclusion

The command design pattern is useful in situations where you want to decouple the object that invokes an action (the invoker) from the object that performs the action (the receiver) by encapsulating the request for the action in an object (the command). This allows you to queue or log requests, as well as support undoable actions. Examples of when you might use the command pattern include implementing undo/redo functionality in a text editor or document editor, implementing a remote control with on/off buttons for a television or other device, and implementing a macro system that allows a user to record and replay a sequence of actions.

Here are a few examples of when you might use the command design pattern:

- Implementing undo/redo functionality in a text editor or document editor. The invoker in this case would be the undo/redo functionality, and the receiver would be the text editor or document editor. The commands would represent the various actions that can be performed on the document, such as inserting or deleting text, formatting text, or moving objects.

- Implementing a remote control with on/off buttons for a television or other device. The invoker in this case would be the remote control, and the receiver would be the television or other device. The commands would represent the various actions that can be performed on the device, such as turning it on or off, adjusting the volume, or changing the channel.

- Implementing a macro system that allows a user to record and replay a sequence of actions. The invoker in this case would be the macro system, and the receiver would be the application in which the actions are being performed. The commands would represent the various actions that can be performed in the application, such as clicking on buttons, entering text, or dragging and dropping objects.

- Implementing a game with a history of moves that can be undone and redone. The invoker in this case would be the undo/redo functionality, and the receiver would be the game. The commands would represent the various moves that can be performed in the game, such as moving a piece on a board or executing an action in a role-playing game.

In all of these examples, the command design pattern allows you to decouple the invoker from the receiver, making it easier to implement undo/redo functionality, queue or log requests, or support other scenarios where you need to manipulate a sequence of actions.

Here is the last example that you can use the command design pattern:

public interface ICommand
{
void Execute();
}

public class ConcreteCommand : ICommand
{
private Receiver _receiver;

public ConcreteCommand(Receiver receiver)
{
_receiver = receiver;
}

public void Execute()
{
_receiver.Action();
}
}

public class Receiver
{
public void Action()
{
Console.WriteLine("Called Receiver.Action()");
}
}

public class Invoker
{
private ICommand _command;

public void SetCommand(ICommand command)
{
_command = command;
}

public void ExecuteCommand()
{
_command.Execute();
}
}

class Program
{
static void Main(string[] args)
{
Receiver receiver = new Receiver();
ICommand command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();

invoker.SetCommand(command);
invoker.ExecuteCommand();

Console.ReadKey();
}
}

As you can see, there is no undo functionality in this sample. Maybe you can modify this sample and add the Undo functionality.

Thanks for reading! If you found the article helpful, you can clap and follow. So you will notified of new articles.

# References

It was created with the help of ChatGPT AI.

--

--

Göksu Deniz

Software Engineer, passionate about creating efficient solutions. Skilled in mentoring teams to deliver successful projects. Always exploring new tech trends.