Command Pattern in C# - What You Need to Implement It

At its core, the command pattern is a behavioral software design pattern that helps separate the logic of a request's execution from its actual implementation. This separation helps to promote greater flexibility and code organization in larger codebases. In this article, I'll go over the command pattern in C# so we can see it in action!

Maintaining well-organized code is crucial for any software engineer, and understanding design patterns -- such as the command pattern -- is an essential part of this process. Together we'll implement the command pattern in C# and you can see if this pattern will help in your current codebase.

Let's dive in!


What's In This Article: The Command Pattern in C#

Remember to follow along on these platforms:

// FIXME: social media icons coming back soon!


Understanding the Command Pattern

The Command Pattern is a behavioral design pattern that decouples the sender of a request from the object that performs the action requested. This software pattern encloses a request as an object, thereby allowing you to parameterize clients with different requests. The object that encapsulates the command may know how to invoke the action, but it doesn't necessarily know the receiver of the request.

In C#, the Command Pattern is used to encapsulate requests as objects, which is particularly helpful in constructing composite commands or transaction processing. The pattern is designed to enable the separation of application-specific functionality from the underlying system, ensuring that changes made to one do not affect the other.

By separating commands from the classes that use them, the command pattern allows you to create a more cohesive and maintainable codebase over time. This separation enables the code to scale and evolve over time without much impact on the system's overall architecture.


Command Pattern Example in C#

Let's say we have a fictional restaurant application where a customer can order a beverage. We would use the Command Pattern to encapsulate the request for the beverage order and its processing. The customer would create a concrete command object, specifying a drink order. The Invoker object, the waiter, sends the Concrete Command object to the receiver, the bartender, which then executes the request.

This separation of roles enables the code to scale and evolve over time while maintaining code modularity and cohesion -- At least, that's the theory behind following a pattern like this. In practice, we may find that the levels of abstraction and separation over-complicate, so it's important to remain pragmatic and choose what works situationally.

Here's an example of implementing the Command Pattern in C#:

// Command
public interface ICommand
{
    void Execute();
}

// Concrete Command
public class BeverageOrderCommand : ICommand
{
    private readonly Beverage _beverage;
    private readonly Bartender _bartender;

    public BeverageOrderCommand(Beverage beverage, Bartender bartender)
    {
        _beverage = beverage;
        _bartender = bartender;
    }

    public void Execute()
    {
        _bartender.ExecuteDrinkOrder(_beverage);
    }
}

// Receiver
public class Bartender
{
    public void ExecuteDrinkOrder(Beverage beverage)
    {
        Console.WriteLine($"Preparing {beverage.Name}");
    }
}

// Invoker
public class Waiter
{
    private readonly ICommand _command;

    public Waiter(ICommand command)
    {
        _command = command;
    }

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

We'll revisit how to put this all together in a later section, so keep on reading!