Command pattern in C#

 Hello, C# lovers! 😍

Today I want to talk to you about one of the most useful and versatile design patterns: the Command pattern. 🙌

The Command pattern is a behavioral pattern that allows you to encapsulate a request as an object and pass it to a receiver. This way, you can decouple the sender and the receiver of the request, and also support undo/redo operations. 🚀

Sounds cool, right? 😎

Let me show you how it works with a simple example in C#: a calculator that can perform different operations: add, subtract, multiply, or divide. 💻

First, we need to define an interface for the command object. It should have two methods: Execute and Unexecute. The Execute method performs the action of the command, and the Unexecute method reverses it.


// The command interface
public interface ICommand
{
    void Execute();
    void Unexecute();
}


Next, we need to create some concrete commands that implement this interface. For each operation, we can create a command that takes the operands and the receiver as parameters.


// A concrete command for addition
public class AddCommand : ICommand { private int x; private int y; private CalculatorReceiver receiver; public AddCommand(int x, int y, CalculatorReceiver receiver) { this.x = x; this.y = y; this.receiver = receiver; } public void Execute() { receiver.Add(x, y); } public void Unexecute() { receiver.Subtract(x, y); // To undo addition, we need to subtract } } // A concrete command for subtraction public class SubtractCommand : ICommand { private int x; private int y; private CalculatorReceiver receiver; public SubtractCommand(int x, int y, CalculatorReceiver receiver) { this.x = x; this.y = y; this.receiver = receiver; } public void Execute() { receiver.Subtract(x, y); } public void Unexecute() { receiver.Add(x, y); // To undo subtraction, we need to add } } // A concrete command for multiplication public class MultiplyCommand : ICommand { private int x; private int y; private CalculatorReceiver receiver; public MultiplyCommand(int x, int y, CalculatorReceiver receiver) { this.x = x; this.y = y; this.receiver = receiver; } public void Execute() { receiver.Multiply(x, y); } public void Unexecute(){

        receiver.Divide(x, y); // To undo multiplication, we need to divide
    }
}


Similarly, we can implement the division command.

// A concrete command for division
public class DivideCommand : ICommand
{
    private int x;
    private int y;
    private CalculatorReceiver receiver;

    public DivideCommand(int x, int y, CalculatorReceiver receiver)
    {
        this.x = x;
        this.y = y;
        this.receiver = receiver;
    }

    public void Execute()
    {
        receiver.Divide(x, y);
    }

    public void Unexecute()
    {
        receiver.Multiply(x, y); // To undo division, we need to multiply
    }
}


Now we need a class that represents the receiver of the commands. This is the class that actually knows how to perform the actions of the commands. In our case, it is the calculator that can perform different operations and display the results.


// The receiver class
public class CalculatorReceiver
{
    public void Add(int x, int y)
    {
        Console.WriteLine($"{x} + {y} = {x + y}");
        // Some logic to perform addition
    }

    public void Subtract(int x, int y)
    {
        Console.WriteLine($"{x} - {y} = {x - y}");
        // Some logic to perform subtraction
    }

    public void Multiply(int x, int y)
    {
        Console.WriteLine($"{x} * {y} = {x * y}");
        // Some logic to perform multiplication
    }

    public void Divide(int x, int y){
        Console.WriteLine($"{x} / {y} = {x / y}");
        // Some logic to perform division
    }
}

Finally, we need a class that acts as the sender or invoker of the commands. This is the class that creates and executes the commands. In our case, it is the calculator service that can accept different operations from users. To support undo/redo functionality, we need to use a stack to store the executed commands.


// The invoker class
public class CalculatorService
{
    private Stack<ICommand> undoStack = new Stack<ICommand>(); // A stack of commands to undo
    private Stack<ICommand> redoStack = new Stack<ICommand>(); // A stack of commands to redo

    public void PerformOperation(ICommand command)
    {
        undoStack.Push(command); // Push the command to the undo stack
        redoStack.Clear(); // Clear the redo stack
        command.Execute(); // Execute the command
    }

    public void UndoOperation()
    {
        if (undoStack.Count > 0)
        {
            ICommand lastCommand = undoStack.Pop(); // Pop the last executed command from the undo stack
            redoStack.Push(lastCommand); // Push it to the redo stack
            lastCommand.Unexecute(); // Unexecute the command
            Console.WriteLine("Undoing last operation");
        }
        else
        {
            Console.WriteLine("No operations to undo");
        }
        
    }

    public void RedoOperation()
    {
        if (redoStack.Count > 0)
        {
            ICommand lastCommand = redoStack.Pop(); // Pop the last unexecuted command from the redo stack
            undoStack.Push(lastCommand); // Push it to the undo stack
            lastCommand.Execute(); // Execute the command
            Console.WriteLine("Redoing last operation");
        }
        else
        {
            Console.WriteLine("No operations to redo");
        }
        
    }
}

And that’s it! We have implemented the Command pattern with undo/redo functionality in C#. 🎉

Now we can use it like this:


// Create a calculator receiver object
CalculatorReceiver receiver = new CalculatorReceiver();

// Create a calculator service object
CalculatorService service = new CalculatorService();

// Create some operation commands with different operands and operations
ICommand addCommand = new AddCommand(10, 5, receiver);
ICommand subtractCommand = new SubtractCommand(10, 5, receiver);
ICommand multiplyCommand = new MultiplyCommand(10, 5, receiver);
ICommand divideCommand = new DivideCommand(10, 5, receiver);

// Use the calculator service to perform operations with different commands
service.PerformOperation(addCommand); // 10 + 5 = 15
service.PerformOperation(subtractCommand); // 10 - 5 = 5
service.PerformOperation(multiplyCommand); // 10 * 5 = 50
service.PerformOperation(divideCommand); // 10 / 5 = 2

// Use the calculator service to undo operations if needed
service.UndoOperation(); // Undoing last operation (10 / 5 = 2)
service.UndoOperation(); // Undoing last operation (10 * 5 = 50)
service.UndoOperation(); // Undoing last operation (10 - 5 = 5)
service.UndoOperation(); // Undoing last operation (10 + 5 = 15)
service.UndoOperation(); // No operations to undo

// Use the calculator service to redo operations if needed
service.RedoOperation(); // Redoing last operation (10 + 5 = 15)
service.RedoOperation(); // Redoing last operation (10 - 5 = 5)
service.RedoOperation(); // Redoing last operation (10 * 5 = 50)
service.RedoOperation(); // Redoing last operation (10 / 5 = 2)
service.RedoOperation(); // No operations to redo

As you can see, the Command pattern allows us to create flexible and extensible code that can handle different types of requests in a uniform way. It also makes it easy to support undo/redo operations by keeping track of the executed and unexecuted commands. 😊


If you want to learn more about the Command pattern and other design patterns in C#, I recommend you check out these resources:


I hope you enjoyed this article and learned something new. If you did, please share it with your friends and colleagues who might be interested in C#. And don’t forget to subscribe to my blog for more awesome content on C#. 😁


You can find the code examples here: source code

Happy coding! 👋

Comments

Popular posts from this blog

Which GOF patterns are good for C#?

Angular on a regular SharePoint page (part 2)

Chain of Responsibility pattern in C#