π§© Command Pattern - C#
The Command Pattern is a behavioral design pattern that encapsulates a request as an object, thereby allowing you to parameterize clients with different requests, queue or log requests, and support undoable operations.
π Key Concepts
- Command: An interface that declares an
Execute() method.
- ConcreteCommand: Implements the
Command interface and defines the binding between a receiver and an action.
- Receiver: The object that performs the actual work when the command is executed.
- Invoker: Stores and invokes commands.
- Client: Creates the command and associates it with the receiver.
βοΈ Why Use Command Pattern?
- Decouples the object that invokes the operation (Invoker) from the one that knows how to perform it (Receiver).
- Makes it easy to add new commands without changing existing code.
- Supports features like undo/redo, logging, and transactional behavior.
π Example in C#
Letβs imagine a simple Remote Control system for a light.
// Command Interface
public interface ICommand
{
void Execute();
void Undo();
}
// Receiver
public class Light
{
public void TurnOn()
{
Console.WriteLine("Light is ON");
}
public void TurnOff()
{
Console.WriteLine("Light is OFF");
}
}
// Concrete Commands
public class LightOnCommand : ICommand
{
private Light _light;
public LightOnCommand(Light light)
{
_light = light;
}
public void Execute()
{
_light.TurnOn();
}
public void Undo()
{
_light.TurnOff();
}
}
public class LightOffCommand : ICommand
{
private Light _light;
public LightOffCommand(Light light)
{
_light = light;
}
public void Execute()
{
_light.TurnOff();
}
public void Undo()
{
_light.TurnOn();
}
}
// Invoker
public class RemoteControl
{
private ICommand _command;
public void SetCommand(ICommand command)
{
_command = command;
}
public void PressButton()
{
_command.Execute();
}
public void PressUndo()
{
_command.Undo();
}
}
// Client
class Program
{
static void Main(string[] args)
{
Light livingRoomLight = new Light();
ICommand lightOn = new LightOnCommand(livingRoomLight);
ICommand lightOff = new LightOffCommand(livingRoomLight);
RemoteControl remote = new RemoteControl();
// Turn light ON
remote.SetCommand(lightOn);
remote.PressButton();
// Undo (turn light OFF)
remote.PressUndo();
// Turn light OFF
remote.SetCommand(lightOff);
remote.PressButton();
// Undo (turn light ON)
remote.PressUndo();
}
}
π Output
Light is ON
Light is OFF
Light is OFF
Light is ON
π Benefits in Real Projects
- GUI Buttons: Each button can be mapped to a command.
- Task Queues: Commands can be queued and executed later.
- Undo/Redo Systems: Each command knows how to reverse its action.
- Macro Commands: Combine multiple commands into one.