Here, we will see how to create Command Design Pattern with example.
The Command Design Pattern is a behavioral pattern that turns requests or operations into objects. This enables you to parameterize methods with different requests, queue or log requests, and support undoable operations.
Let’s consider a home automation system where you can control devices like lights, fans, and TVs. We will explain in detail lator part of the article with code example.
Let’s consider a home automation system where you can control devices like lights, fans, and TVs. Here, I’ll explain the key components and how the pattern works in this context.
Command Interface (ICommand) - This interface defines two methods: Execute() and Undo(). Any class implementing this interface will encapsulate an action (e.g., turning on or off a device) and its corresponding undo action.
Receivers (Light, Fan, TV) - These are the classes that know how to perform the actual work. They are the devices that will be controlled by the commands. For instance, the Light class has methods to turn the light on and off.
Concrete Command Classes
Invoker (RemoteControl)
Client Code
C# Code Example
using System;
using System.Collections.Generic;
// Command Interface
public interface ICommand
{
void Execute();
void Undo();
}
// Light Class (Receiver)
public class Light
{
public void TurnOn() => Console.WriteLine("Light is On");
public void TurnOff() => Console.WriteLine("Light is Off");
}
// Fan Class (Receiver)
public class Fan
{
public void TurnOn() => Console.WriteLine("Fan is On");
public void TurnOff() => Console.WriteLine("Fan is Off");
}
// TV Class (Receiver)
public class TV
{
public void TurnOn() => Console.WriteLine("TV is On");
public void TurnOff() => Console.WriteLine("TV is Off");
}
// Concrete Commands for Light
public class TurnOnLightCommand : ICommand
{
private Light _light;
public TurnOnLightCommand(Light light)
{
_light = light;
}
public void Execute() => _light.TurnOn();
public void Undo() => _light.TurnOff();
}
public class TurnOffLightCommand : ICommand
{
private Light _light;
public TurnOffLightCommand(Light light)
{
_light = light;
}
public void Execute() => _light.TurnOff();
public void Undo() => _light.TurnOn();
}
// Concrete Commands for Fan
public class TurnOnFanCommand : ICommand
{
private Fan _fan;
public TurnOnFanCommand(Fan fan)
{
_fan = fan;
}
public void Execute() => _fan.TurnOn();
public void Undo() => _fan.TurnOff();
}
public class TurnOffFanCommand : ICommand
{
private Fan _fan;
public TurnOffFanCommand(Fan fan)
{
_fan = fan;
}
public void Execute() => _fan.TurnOff();
public void Undo() => _fan.TurnOn();
}
// Concrete Commands for TV
public class TurnOnTVCommand : ICommand
{
private TV _tv;
public TurnOnTVCommand(TV tv)
{
_tv = tv;
}
public void Execute() => _tv.TurnOn();
public void Undo() => _tv.TurnOff();
}
public class TurnOffTVCommand : ICommand
{
private TV _tv;
public TurnOffTVCommand(TV tv)
{
_tv = tv;
}
public void Execute() => _tv.TurnOff();
public void Undo() => _tv.TurnOn();
}
// Invoker (Remote Control)
public class RemoteControl
{
private ICommand _command;
public void SetCommand(ICommand command)
{
_command = command;
}
public void PressButton()
{
_command.Execute();
}
public void PressUndo()
{
_command.Undo();
}
}
// Client Code
public class Client
{
public static void Main(string[] args)
{
// Create Receivers
Light light = new Light();
Fan fan = new Fan();
TV tv = new TV();
// Create Concrete Commands for each device
ICommand turnOnLight = new TurnOnLightCommand(light);
ICommand turnOffLight = new TurnOffLightCommand(light);
ICommand turnOnFan = new TurnOnFanCommand(fan);
ICommand turnOffFan = new TurnOffFanCommand(fan);
ICommand turnOnTV = new TurnOnTVCommand(tv);
ICommand turnOffTV = new TurnOffTVCommand(tv);
// Create Invoker (Remote Control)
RemoteControl remote = new RemoteControl();
// Turn On Light
remote.SetCommand(turnOnLight);
remote.PressButton(); // Output: Light is On
remote.PressUndo(); // Output: Light is Off
// Turn On Fan
remote.SetCommand(turnOnFan);
remote.PressButton(); // Output: Fan is On
remote.PressUndo(); // Output: Fan is Off
// Turn On TV
remote.SetCommand(turnOnTV);
remote.PressButton(); // Output: TV is On
remote.PressUndo(); // Output: TV is Off
}
}
Light
,
Fan
, and TV
).Execute()
method of the command, which internally calls the appropriate method on the
receiver.Output
A text editor is a classic real-world example of the command pattern. Each text modification operation (like typing, deleting, or formatting) is encapsulated as a command object, which can be undone or redone. The text editor maintains a history of commands, allowing the user to undo or redo any number of previous actions.
The program has:
C# Code
using System;
using System.Collections.Generic;
// Command interface
public interface ICommand
{
void Execute();
void UnExecute();
}
// Text Editor class that maintains text and supports actions
public class TextEditor
{
public string Text { get; set; } = string.Empty;
public void AddText(string text)
{
Text += text;
}
public void RemoveText(int length)
{
if (length <= Text.Length)
{
Text = Text.Substring(0, Text.Length - length);
}
}
public override string ToString()
{
return Text;
}
}
// Concrete command for adding text (Typing)
public class AddTextCommand : ICommand
{
private readonly TextEditor _textEditor;
private readonly string _textToAdd;
public AddTextCommand(TextEditor textEditor, string textToAdd)
{
_textEditor = textEditor;
_textToAdd = textToAdd;
}
public void Execute()
{
_textEditor.AddText(_textToAdd);
}
public void UnExecute()
{
_textEditor.RemoveText(_textToAdd.Length);
}
}
// Command Invoker which stores the command history for undo/redo
public class CommandInvoker
{
private readonly Stack<ICommand> _undoCommands = new Stack<ICommand>();
private readonly Stack<ICommand> _redoCommands = new Stack<ICommand>();
public void ExecuteCommand(ICommand command)
{
command.Execute();
_undoCommands.Push(command);
_redoCommands.Clear(); // Clear redo history after a new command
}
public void Undo()
{
if (_undoCommands.Count > 0)
{
var command = _undoCommands.Pop();
command.UnExecute();
_redoCommands.Push(command);
}
}
public void Redo()
{
if (_redoCommands.Count > 0)
{
var command = _redoCommands.Pop();
command.Execute();
_undoCommands.Push(command);
}
}
}
// Example of usage
public class Program
{
public static void Main(string[] args)
{
var editor = new TextEditor();
var invoker = new CommandInvoker();
Console.WriteLine("Initial Text: " + editor);
// Typing "Hello "
invoker.ExecuteCommand(new AddTextCommand(editor, "Hello "));
Console.WriteLine("After Typing: " + editor);
// Typing "World!"
invoker.ExecuteCommand(new AddTextCommand(editor, "World!"));
Console.WriteLine("After Typing: " + editor);
// Undo last typing (remove "World!")
invoker.Undo();
Console.WriteLine("After Undo: " + editor);
// Redo last action (add "World!" again)
invoker.Redo();
Console.WriteLine("After Redo: " + editor);
// Undo typing "World!" and "Hello "
invoker.Undo();
invoker.Undo();
Console.WriteLine("After Undoing Twice: " + editor);
// Redo one action (add "Hello " back)
invoker.Redo();
Console.WriteLine("After Redo Once: " + editor);
}
}
Output