C# Command Pattern

Summary: in this tutorial, you’ll learn about the C# Command design pattern and how to use it to make your application more flexible and extensible.

Introduction to the C# command design pattern

The Command pattern is a behavioral design pattern that encapsulates a request as an object, thereby allowing the requester to be decoupled from the object that operates.

The Command pattern encapsulates the request as a command object that contains all the necessary information to execute the request.

The requester doesn’t need to know the details of how the command is executed. Instead, it simply requests the execution of the command by calling its execute method.

This makes your application more flexible and extensible because the requester can easily switch out different commands without the need of understanding how those commands are executed.

Because the command object stores the necessary information to reverse or replay the operation, the Command pattern enables features like undo and redo.

C# Command pattern structure

The following UML diagram illustrates the Command design pattern:

c# Command design pattern

In this diagram:

  • ICommand: Defines the interface for executing an operation.
  • ConcreteCommand: Implements the ICommand interface and defines the binding between a Receiver object and an action. The ConcreteCommand implements the Execute() and Undo() method by calling the corresponding operations on the Receiver object.
  • Client: Creates ConcreteCommand objects and sets their receivers.
  • Receiver: Knows how to perform the operations associated with carrying out a request.
  • Invoker: Asks the command to carry out the request.

Collaboration between participants:

  • The Client creates a ConcreteCommand object and tells it which receiver object should receive the command.
  • An Invoker object saves the ConcreteCommand object.
  • The Invoker calls the Execute method on the ICommand object to carry out the request. If the command is undoable, the ConcreteCommand object stores information needed to undo the command before calling Execute method.
  • The ConcreteCommand object then directs the Receiver to perform the necessary actions to fulfill the request.

The following shows how to implement the command pattern in C# (without Undo() method, more on this in the next example):

namespace CommandDesignPattern;

public interface ICommand
{
    void Execute();
}

public class Receiver
{
    public void Action()
    {
        Console.WriteLine("Perform an action");
    }
}

public class ConcreteCommand : ICommand
{
    private Receiver Receiver
    {
        get; set;
    }
    public ConcreteCommand(Receiver receiver)
    {
        Receiver = receiver;
    }

    public void Execute() => Receiver.Action();
}

public class Invoker
{
    public ICommand? Command
    {
        get; set;
    }

    public void Invoke() => Command?.Execute();

}

class Client
{
    public static void Main(string[] args)
    {
        var receiver = new Receiver();
        var concreteCommand = new ConcreteCommand(receiver);

        var invoker = new Invoker
        {
            Command = concreteCommand
        };

        invoker.Invoke();

    }
}Code language: C# (cs)

C# Command pattern example

The following program defines a Calculator class with methods for basic arithmetic operations including adding, subtracting, multiplying, and dividing that update the current value.

In the Main() method of the Program class, we create an instance of the Calculator class, add 20 to the current value, subtract 5 from it, and then display the current value of the calculator in the console:

namespace CommandPattern;

public class Calculator
{
    public double CurrentValue
    {
        get; private set;
    }
    public double Add(double valueToAdd) => CurrentValue += valueToAdd;
    public double Subtract(double valueToSubtract) => CurrentValue -= valueToSubtract;
    public double Divide(double valueToDivide) => CurrentValue /= valueToDivide;
    public double Mutiply(double valueToMultiply) => CurrentValue *= valueToMultiply;

}

public class Program
{
    public static void Run(string[] args)
    {
        var calculator = new Calculator();
        calculator.Add(20);
        calculator.Subtract(5);

        Console.WriteLine(calculator.CurrentValue);
    }
}Code language: C# (cs)

Output:

15Code language: C# (cs)

The program currently doesn’t support the undo feature because it is not using the Command pattern. To add the undo feature, we can refactor the program by applying the Command pattern:

namespace CommandPattern;

public interface ICommand
{
    double Execute(double value);
    double Undo(double value);
}

public class AddCommand : ICommand
{
    private readonly double _valueToAdd;
    public AddCommand(double valueToAdd)
    {
        _valueToAdd = valueToAdd;
    }

    public double Execute(double currentValue) => currentValue += _valueToAdd;
    public double Undo(double currentValue) => currentValue -= _valueToAdd;
}

public class SubtractCommand : ICommand
{
    private readonly double _valueToSubtract;
    public SubtractCommand(double valueToSubtract)
    {
        _valueToSubtract = valueToSubtract;
    }
    public double Execute(double currentValue) => currentValue -= _valueToSubtract;
    public double Undo(double currentValue) => currentValue += _valueToSubtract;
}

public class DivideCommand : ICommand
{
    private readonly double _valueToDivide;
    public DivideCommand(double valueToDivide)
    {
        _valueToDivide = valueToDivide;
    }
    public double Execute(double currentValue) => currentValue /= _valueToDivide;
    public double Undo(double currentValue) => currentValue *= _valueToDivide;
}

public class MultiplyCommand : ICommand
{
    private readonly double _valueToMultiply;
    public MultiplyCommand(double valueToMultiply)
    {
        _valueToMultiply = valueToMultiply;
    }
    public double Execute(double currentValue) => currentValue *= _valueToMultiply;
    public double Undo(double currentValue) => currentValue /= _valueToMultiply;
}

public class Calculator
{
    public double CurrentValue
    {
        get; private set;
    }

    public Stack<ICommand> _commandHistory = new();

    public void ExecuteCommand(ICommand command)
    {
        CurrentValue = command.Execute(CurrentValue);
        _commandHistory.Push(command);
    }

    public void Undo()
    {
        var command = _commandHistory.Pop();
        CurrentValue = command.Undo(CurrentValue);
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var calculator = new Calculator();
        calculator.ExecuteCommand(new AddCommand(20));
        calculator.ExecuteCommand(new SubtractCommand(10));
        calculator.ExecuteCommand(new MultiplyCommand(5));
        Console.WriteLine(calculator.CurrentValue);

        calculator.Undo();
        Console.WriteLine(calculator.CurrentValue);
    }
}Code language: C# (cs)

How it works.

First, create an ICommand interface that has two methods Execute and Undo:

public interface ICommand
{
    double Execute(double value);
    double Undo(double value);
}Code language: C# (cs)

Second, define the AddCommand that implements the ICommand interface. The AddCommand adds a value to a current value:

public class AddCommand : ICommand
{
    private readonly double _valueToAdd;
    public AddCommand(double valueToAdd)
    {
        _valueToAdd = valueToAdd;
    }

    public double Execute(double currentValue) => currentValue += _valueToAdd;
    public double Undo(double currentValue) => currentValue -= _valueToAdd;
}Code language: C# (cs)

The Execute() method adds a value to the current value. And the Undo() method subtracts the same value from the current value.

Similarly, define the SubtractCommand, MultiplyCommand, and DivideCommand classes:

public class SubtractCommand : ICommand
{
    private readonly double _valueToSubtract;
    public SubtractCommand(double valueToSubtract)
    {
        _valueToSubtract = valueToSubtract;
    }
    public double Execute(double currentValue) => currentValue -= _valueToSubtract;
    public double Undo(double currentValue) => currentValue += _valueToSubtract;
}

public class DivideCommand : ICommand
{
    private readonly double _valueToDivide;
    public DivideCommand(double valueToDivide)
    {
        _valueToDivide = valueToDivide;
    }
    public double Execute(double currentValue) => currentValue /= _valueToDivide;
    public double Undo(double currentValue) => currentValue *= _valueToDivide;
}

public class MultiplyCommand : ICommand
{
    private readonly double _valueToMultiply;
    public MultiplyCommand(double valueToMultiply)
    {
        _valueToMultiply = valueToMultiply;
    }
    public double Execute(double currentValue) => currentValue *= _valueToMultiply;
    public double Undo(double currentValue) => currentValue /= _valueToMultiply;
}Code language: C# (cs)

Third, define the Calculator class that executes a command and undoes it:

public class Calculator
{
    public double CurrentValue
    {
        get; private set;
    }

    public Stack<ICommand> _commandHistory = new();

    public void ExecuteCommand(ICommand command)
    {
        CurrentValue = command.Execute(CurrentValue);
        _commandHistory.Push(command);
    }

    public void Undo()
    {
        var command = _commandHistory.Pop();
        CurrentValue = command.Undo(CurrentValue);
    }
}Code language: C# (cs)

The Calculator class has a CurrentValue property that represents its current value. Also, it has a private field _commandHistory that keeps track of previously executed commands.

The ExecuteCommand method takes an ICommand object. The method calls the Execute() method of an ICommand object with the current value of the calculator and then adds the ICommand object to the command history stack.

The Undo method pops the most recent command off of the command history stack, calls the Undo method of the command with the current value of the calculator, and updates the CurrentValue property with the result.

Finally, define the Program class that demonstrates the ability to execute and undo commands using the Command pattern:

public class Program
{
    public static void Main(string[] args)
    {
        var calculator = new Calculator();
        calculator.ExecuteCommand(new AddCommand(20)); // -> 20
        calculator.ExecuteCommand(new SubtractCommand(10)); // -> 10
        calculator.ExecuteCommand(new MultiplyCommand(5)); // -> 50
        Console.WriteLine(calculator.CurrentValue); // output 50

        calculator.Undo(); // 10
        Console.WriteLine(calculator.CurrentValue); // output 10
    }
}Code language: C# (cs)

Output:

50
10Code language: C# (cs)

In the Main() method:

  • First, create a new instance of the Calculator class.
  • Next, execute three commands including AddCommand, SubtractCommand, and MultiplyCommand using the ExecuteCommand method of the Calculator object with the appropriate arguments (20, 10, and 5, respectively).
  • Then, display the CurrentValue of the Calculator object to the console.
  • After that, call the Undo method of the Calculator object, which undoes the most recent command (the MultiplyCommand in this case) and updates the CurrentValue property of the Calculator object with the result of the undo operation.
  • Finally, print the updated current value of the calculator to the console.

In this program, the following objects map to the Command pattern:

  • ICommand interface: defines the common methods that all concrete commands should implement.
  • AddCommand, SubtractCommand, MultiplyCommand, and DivideCommand classes: concrete commands that implement the ICommand interface and encapsulate the operations that can be executed on the CurrentValue property of the Calculator object.
  • Calculator class: the invoker that receives and stores the concrete commands. It executes the commands by calling their Execute methods, and undoes them by calling their Undo methods.
  • Program class: the client that creates a Calculator object and executes the concrete commands on it. It also invokes the Undo method of the Calculator object to undo the last executed command.

Summary

  • Use the command pattern to decouple the requester and receiver of a request by encapsulating the request as an object.
Was this tutorial helpful ?