Post

C# | Command Design Pattern

The Command Pattern is a behavioral design pattern that turns a request into a standalone object. This object contains all the information about the request, allowing for parameterization of clients with different requests, queuing of requests, and logging of the operations. It also supports undoable operations.

Key Components:

  1. Command:
    • Defines an interface for executing a particular operation.
    • Typically includes an Execute method.
  2. ConcreteCommand:
    • Implements the Command interface.
    • Holds the information about the operation to be executed.
    • Invokes the operation through a receiver.
  3. Invoker:
    • Asks the command to execute the request.
    • Does not know how the request is handled.
  4. Receiver:
    • Knows how to perform the operation.
    • Can be any object that can perform the requested action.
  5. Client:
    • Creates a Command object and associates it with a Receiver.
    • Passes the command to the invoker.

Example in C#:

Let’s consider a simple example of a remote control that can turn on and off devices:

1. Command Interface:

1
2
3
4
public interface ICommand
{
    void Execute();
}

2. Concrete Commands:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class LightOnCommand : ICommand
{
    private readonly Light _light;

    public LightOnCommand(Light light)
    {
        _light = light;
    }

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

public class LightOffCommand : ICommand
{
    private readonly Light _light;

    public LightOffCommand(Light light)
    {
        _light = light;
    }

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

3. Receiver:

1
2
3
4
5
6
7
8
9
10
11
12
public class Light
{
    public void TurnOn()
    {
        Console.WriteLine("Light is ON");
    }

    public void TurnOff()
    {
        Console.WriteLine("Light is OFF");
    }
}

4. Invoker:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class RemoteControl
{
    private ICommand _command;

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

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

5. Client Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Program
{
    static void Main()
    {
        Light livingRoomLight = new Light();
        ICommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
        ICommand livingRoomLightOff = new LightOffCommand(livingRoomLight);

        RemoteControl remote = new RemoteControl();

        remote.SetCommand(livingRoomLightOn);
        remote.PressButton(); // Light is ON

        remote.SetCommand(livingRoomLightOff);
        remote.PressButton(); // Light is OFF
    }
}

In this example, the RemoteControl acts as the invoker, and the commands (LightOnCommand and LightOffCommand) encapsulate the operations. The Light class is the receiver that knows how to perform the requested actions.

What Next?

The Command Pattern provides flexibility and decouples the sender and receiver of a request, making it easier to extend and maintain the code.

This post is licensed under CC BY 4.0 by the author.