Command Design Pattern in C# with Example

1. Definition

Encapsulate a request as an object, thereby allowing for parameterization of clients with different requests, queuing of requests, and logging of operations.

2. Problem Statement

Imagine building a smart home system where you have different appliances and devices, and you want to control them via a central remote control or voice commands. How do you ensure that adding new commands or devices doesn't complicate the code? And how do you enable features like undo and redo for these operations?

3. Solution

The Command pattern can help by encapsulating each operation in a command object. This object can then be passed, stored, and executed at the appropriate time. The invoker or sender and the receiver are decoupled, leading to a more modular and extensible system.

4. Real-World Use Cases

1. Implementing 'undo' and 'redo' functionalities in software applications.

2. Operations queue in task scheduling systems.

3. Remote controls for devices.

5. Implementation Steps

1. Define a command interface with an 'Execute' method.

2. Create one or more derived classes that encapsulate a receiver object with an action.

3. Define classes for the invoker and client.

4. The client creates command objects and sets its receiver.

6. Implementation in C#

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

// Step 2: Concrete Command
public class LightOnCommand : ICommand
{
    private Light _light;

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

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

public class Light
{
    public void TurnOn()
    {
        Console.WriteLine("Light is ON");
    }
}

// Step 3: Invoker class
public class RemoteControl
{
    private ICommand _command;

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

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

public class Program
{
    public static void Main()
    {
        // Client code
        Light light = new Light();
        ICommand lightOn = new LightOnCommand(light);

        RemoteControl remote = new RemoteControl();
        remote.SetCommand(lightOn);
        remote.PressButton();
    }
}

Output:

Light is ON

Explanation:

The Light is the receiver here, and the LightOnCommand encapsulates the command to turn the light on. 

The RemoteControl is the invoker. When the PressButton method is called, it invokes the command to execute the associated action.

7. When to use?

1. Use the Command pattern when you want to parameterize objects with operations.

2. When you need to queue operations, schedule their execution, or execute remote operations.

3. When you want to implement reversible operations (e.g., undo and redo).


Comments