Why Command Pattern Is Actually Good for Your C# Code


Getting your code to do what you want can be challenging. You have to ensure all the pieces are in the right place, which can be difficult when you’re working with a lot of code. One of the challenges you might find in the code is passing an action request from one object to another. That’s where the Command design pattern can help you.

In software engineering, the Command design pattern is a behavioral design pattern that encapsulates a request as an object, thereby allowing for the parameterization of clients with different requests and providing a historical record of requests. It also allows for the reversal of requests.

This article will teach you about the Command pattern and why it is good for your C# code. So stay tuned and keep learning!

What is the Command design pattern?

command pattern in a nutshell

Design patterns are a way to solve a recurring problem. A group of four computer scientists, the Gang of Four, proposed 23 design patterns.

They described different problem-solving strategies in their patterns. 

The Command design pattern is a behavioral design pattern that encapsulates a request as an object and lets you parameterize other objects with requests, queues, or logs. Whenever a client requests, it is encapsulated as an object and passed to the invoker object.

The Invoker then searches for the appropriate object to handle the Command and passes it to the corresponding object that can execute it. The object, called Command, contains all the information needed to perform an action or trigger an event, such as the method name, the method owner, and the arguments for method parameters.

Conceptual Example

Suppose you go to a restaurant and a waiter approaches you to take the order. After ensuring everything is as per your request, the waiter requests the order from you.

After taking the order and noting it on paper, he pastes it in the kitchen. After some time, when the chef sees your order, he will cook your food according to the instructions. He will also set the tray with food and the paper where the waiter took the order.

In the above example, the paper on which the waiter took the order is the Command that remains in the queue unless the chef discovers it. The chef is the Receiver who knows exactly what to do, and the waiter is the Invoker who will take the order from you, take it to the chef and bring back the result you requested.

When to use the Command design pattern?

Every design pattern in programming has different applications. For example, you can use some to connect two or more incompatible interfaces. Meanwhile, others avoid the expensive creation of larger objects, etc. Similarly, you can apply the Command design pattern in the following scenarios.

When you want to parameterize objects by the actions to perform

The Command pattern is super implementable in cases where you want to grab the current information from the graphical user interface and take action based on that information.

Specify, queue, and execute requests at different times

It would be best to use the Command pattern when handling multiple requests at various times. 

Support undo

When you want to track the commands that were performed, i.e., when you want to undo or redo the previous commands.

Support logging changes so that they can be reapplied if the system crashes

When you want to add logging to all of the commands that will be performed or are complete, you can reapply them if the system crashes.

Structure a system around high-level operations built from primitive operations

You use the Command pattern when you want to build the system with general components that do not need to know which methods are called.

Who are the participants of the Command design pattern?

The class diagram below will help you understand the structure of the Command design pattern.

command design pattern uml diagram

The participants in this design pattern are:

  • Client – The Client is responsible for creating the ConcreteCommand object and setting its Receiver.
  • Invoker – The caller of the request.
  • Command – Declares an interface for performing an action or executing an operation.
  • ConcreteCommand – Responsible for binding Receiver object and an action. It invokes the corresponding operation on the Receiver by implementing Execute interface.
  • Receiver – performs the operations associated with carrying out a request.

The Client will send the request that will be turned into a command, i.e., encapsulated object. The Invoker will take the Command to the appropriate object that can execute the Command properly and will call the Receiver functions to complete the operation.

How to implement the Command design pattern in C#

The following steps show you how to implement the Command pattern in C#:

  • Step 1: Declaration of the Command interface having a single Execute method.
  • Step 2: Implement the Command interface through the ConcreteCommand classes, each having fields to store request arguments and a reference to the receiver.
  • Step 3: Identify the Invoker classes, add fields for storing commands into these classes, and make sure they communicate with their commands only via the Command interface.
  • Step 4: Make Invokers execute the commands rather than sending requests to the receiver directly.
  • Step 5: Create the objects in the client class in the following sequence:
    • The Receiver object
    • The Command object calling the ConcreteCommand constructor and associated with the corresponding Receivers
    • The Invoker objects associated with their appropriate commands

Command design pattern – structural code in C#

Let’s take a look at the structural code.

//The interface that Encapsulates the request
public interface Command
{
    public void Execute();
}

//Concrete class based on the interface
//that actually calls the method
public class ConcreteCommand : Command
{
    private Receiver receiver;
    public ConcreteCommand(Receiver receiver)
    {
        this.receiver = receiver;
    }
    public void Execute()
    {
        receiver.Action();
    }
}

//Receiver who knows the operation the actual operation
public class Receiver
{
    public void Action()
    {
        Console.Write("Calling Receiver's Action");
    }
}

//The caller of the Command
public class Invoker
{
    Command command;
    public Invoker(Command command)
    {
        this.command = command;
    }

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

And the usage.

Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker(command);
invoker.ExecuteCommand();

It produces the following output.

Calling Receiver's Action

Command pattern – Real-world example in C#

The programmers use the command pattern extensively due to its usability. In C#, you will find many real-world examples. The following example implements the command pattern to open a document whenever the Client chooses to open it. You can expand this example by adding the functionality of creating or deleting the files. To keep things simple, the following example demonstrates only the Open feature.

/The interface that Encapsulates the request
//This is the Command interface
public interface IDocument
{
    public void Execute();
}

//Concrete class based on the interface that
//actually calls the method
//It is the ConcreteCommand class
public class OpenDoc : IDocument

{
    private Doc document;
    public OpenDoc(Doc document)
    {
        this.document = document;
    }
    public void Execute()
    {
        document.Open();
    }
}

//Receiver who knows the operation to perform
public class Doc
{
    public void Open()
    {
        Console.Write("Opening the Document");
    }
}

//The Invoker of the Command
public class Menu
{
    IDocument document;
    public Menu(IDocument document)
    {
        this.document = document;
    }

    public void OpenDocument()
    {
        document.Execute();
    }
}

And the program that uses the above code:

Doc document = new Doc();
IDocument doc = new OpenDoc(document);
Menu menu = new Menu(doc);
menu.OpenDocument();

In this example:

  • The IDocument is the Command.
  • The OpenDoc is the ConcreteCommand.
  • The Doc is the Receiver.
  • The Menu is the Invoker.
  • The Program class is the Client.

Output:

Opening the Document

Advantages of using the Command design pattern

You will find many advantages of using command design pattern if you explore it, some of which are as follows:

  • It is an extensible design pattern that allows you to add more commands without changing or disturbing the existing classes and code.
  • Provides you with a queue system to create a sequence of commands.
  • Decouples the classes from the object that knows how to perform the operation. 
  • Undoing and redoing is implementable.
  • Allows you to implement deferred execution of operations.
  • Assembles a set of simple commands into complex ones.

Main disadvantage of using the Command pattern

The only disadvantage of using the command pattern is the complicated code, which introduces a whole new layer between Sender and Receiver.

What are the related patterns to the Command design pattern?

The Command pattern is related to multiple patterns, out of which the majors are Prototype, Memento, and Composite design patterns. The Prototype design pattern can help when the history contains the copies of the Command. You can use the Command and Momento together to implement the “undo” feature.

The Command operates on the object; meanwhile, the Momento saves the object’s state just before the operation is complete. The relationship between the Composite and Command patterns is that the Composite represents a group of Commands.

Considerations when implementing the Command design pattern

Although the implementation of the Command design pattern may seem simple and easy while implementing it, consider the following parameters.

How intelligent should a command be?

Consider how much intelligence and depth are required for a command to become implementable for handling multiple requests simultaneously. It can have a range of abilities, from barely defining the binding between the Receiver and the request to implementing everything without delegating anything to a receiver. 

Supporting Undo and redo

Check if the Command supports undo and redo function or not. If not, check if the system requires this functionality or not. A command can only support these capabilities if it can reverse their execution. In that case, the ConcreteCommand will have to implement additional states that include:

  • A Receiver object to carrying out operations in response to the requests.
  • The arguments passed to the operation done on the Receiver.
  • The original values of the receiver in case they change by the operation done on it. 

How to avoid error accumulation during undo process?

Think about how you will avoid any errors while undoing something. Find ways to accumulate the errors, if any. The errors will generate when you execute, unexecute and re-execute a command several times. One way to avoid such issues is to store more information in the commands so that you can restore the objects to their original state. 

Does Command design pattern increase coupling?

The Command design pattern supports loose coupling between two classes, i.e., the Invoker and the Receiver. The Invoker class will call a method on the Receiver class to operate.

What is the CQS pattern?

The CQS stands for Command Query Separation. It is a design principle that implies that a method could either be a command that performs an operation or a query that returns the data to the caller but can never be both simultaneously.

According to this principle, when a method is a command, it will change the object’s internal state without returning any data. In contrast, when it is a query, it will return the data without changing the object’s internal state.

What is the Command in MVVM?

In Model-View View-Model architecture, the Command is a separation between the user interface and the logic. It is an object that implements the ICommand interface and is associated with a function in the code.

The elements on the user interface are bound to the commands, i.e., when a user performs an action, the Command invokes the function associated with that element. 

Conclusion

Design patterns are a powerful tool for software developers. They provide a way to write more maintainable, readable, and scalable code.

The Command pattern is a way to encapsulate a request as an object. This allows the request to be handled uniformly, regardless of who is executing it. The Command pattern lets you encapsulate the information inside an object called a command.

It is a useful design pattern, extensively used in applications where the components do not require knowing the working method. For example, you can use it to implement your applications’ undo and redo functionality.

It is related to Prototype, Memento, and Composite patterns. This article discussed the Command design pattern with structural code, a class diagram, and a real-world example.

If you want to learn more about design patterns, check the separate in-depth article about design patterns in C#.

Recent Posts