Back to: Design Patterns in C# With Real-Time Examples
Real-Time Examples of Command Design Patterns in C#
I will discuss the Real-Time Examples of the Command Design Pattern in C# in this article. Please read our previous article discussing the basic concepts of Command Design Patterns in C# with Examples. At the end of this article, you will understand the following Real-time Examples using the Command Design Pattern in C#.
- Remote Control for a Television
- Restaurant Order System
- Smart Home System
- Simple Graphics Editor
- Banking System
- Text Editor
- Music Player Application
- E-Commerce Shopping Cart System
Real-Time Example of Command Design Pattern in C#: Remote Control for a Television
Suppose you have a remote control with buttons for turning the TV on, turning it off, increasing the volume, and decreasing the volume. Each button press is a command the TV (the receiver) must execute. Let us see how we can implement the above example using Command Design Pattern in C#:
using System; namespace CommandDesignPattern { //Command Interface public interface ICommand { void Execute(); } //Receiver - Television public class Television { public void TurnOn() { Console.WriteLine("TV is ON"); } public void TurnOff() { Console.WriteLine("TV is OFF"); } public void VolumeUp() { Console.WriteLine("Volume Increased"); } public void VolumeDown() { Console.WriteLine("Volume Decreased"); } } //Concrete Commands public class TurnOnCommand : ICommand { private Television _tv; public TurnOnCommand(Television tv) { _tv = tv; } public void Execute() { _tv.TurnOn(); } } public class TurnOffCommand : ICommand { private Television _tv; public TurnOffCommand(Television tv) { _tv = tv; } public void Execute() { _tv.TurnOff(); } } public class VolumeUpCommand : ICommand { private Television _tv; public VolumeUpCommand(Television tv) { _tv = tv; } public void Execute() { _tv.VolumeUp(); } } public class VolumeDownCommand : ICommand { private Television _tv; public VolumeDownCommand(Television tv) { _tv = tv; } public void Execute() { _tv.VolumeDown(); } } //Invoker - Remote Control public class RemoteControl { private ICommand _command; public void SetCommand(ICommand command) { _command = command; } public void PressButton() { _command.Execute(); } } // Testing the Command Design Pattern // Client Code public class Program { public static void Main(string[] args) { Television tv = new Television(); ICommand turnOn = new TurnOnCommand(tv); ICommand turnOff = new TurnOffCommand(tv); ICommand volumeUp = new VolumeUpCommand(tv); ICommand volumeDown = new VolumeDownCommand(tv); RemoteControl remote = new RemoteControl(); remote.SetCommand(turnOn); remote.PressButton(); remote.SetCommand(volumeUp); remote.PressButton(); remote.PressButton(); // Increase volume again remote.SetCommand(turnOff); remote.PressButton(); Console.ReadKey(); } } }
This example demonstrates how the Command pattern allows for creating a flexible and extensible remote-control system. If we were to add more functionalities, like changing channels or accessing a menu, it would be a matter of creating additional command classes and integrating them into the remote without altering the existing codebase significantly. When you run the above code, you will get the following output.
Real-Time Example of Command Design Pattern in C#: Restaurant Order System
In a restaurant, a waiter takes orders from customers. Each order can be seen as a command. The kitchen (or chef) is the receiver that will execute these commands. The waiter doesn’t need to know how a dish is prepared; they must pass the order (command) to the kitchen. Let us see how we can implement the above example using Command Design Pattern in C#:
using System; using System.Collections.Generic; namespace CommandDesignPattern { //Command Interface public interface IOrderCommand { void Execute(); } //Receiver - Kitchen public class Kitchen { public void PreparePasta() { Console.WriteLine("Preparing Pasta..."); } public void PrepareBurger() { Console.WriteLine("Preparing Burger..."); } } //Concrete Commands public class PastaOrderCommand : IOrderCommand { private Kitchen _kitchen; public PastaOrderCommand(Kitchen kitchen) { _kitchen = kitchen; } public void Execute() { _kitchen.PreparePasta(); } } public class BurgerOrderCommand : IOrderCommand { private Kitchen _kitchen; public BurgerOrderCommand(Kitchen kitchen) { _kitchen = kitchen; } public void Execute() { _kitchen.PrepareBurger(); } } //Invoker - Waiter public class Waiter { private List<IOrderCommand> _orders = new List<IOrderCommand>(); public void TakeOrder(IOrderCommand orderCommand) { _orders.Add(orderCommand); } public void PlaceOrders() { foreach (var order in _orders) { order.Execute(); } _orders.Clear(); } } // Testing the Command Design Pattern // Client Code public class Program { public static void Main(string[] args) { Kitchen kitchen = new Kitchen(); IOrderCommand pastaOrder = new PastaOrderCommand(kitchen); IOrderCommand burgerOrder = new BurgerOrderCommand(kitchen); Waiter waiter = new Waiter(); waiter.TakeOrder(pastaOrder); waiter.TakeOrder(burgerOrder); // Later, the waiter sends all orders to the kitchen waiter.PlaceOrders(); Console.ReadKey(); } } }
In this example, the Command pattern allows the system to add more dishes or modify existing ones easily. The waiter (Invoker) remains decoupled from the preparation details, and the kitchen (Receiver) is only concerned with how to prepare the dishes. This kind of abstraction and separation of concerns makes the restaurant system flexible and maintainable. When you run the above code, you will get the following output.
Real-Time Example of Command Design Pattern in C#: Smart Home System
In a smart home, a user can use voice commands to control devices such as lights, fans, and thermostats. Each voice command corresponds to an operation a specific device needs to execute. Let us see how we can implement the above example using Command Design Pattern in C#:
using System; namespace CommandDesignPattern { //Command Interface public interface ICommand { void Execute(); } //Receivers //Receiver - Light public class Light { public void TurnOn() { Console.WriteLine("Light turned ON"); } public void TurnOff() { Console.WriteLine("Light turned OFF"); } } //Receiver - Fan public class Fan { public void Start() { Console.WriteLine("Fan started"); } public void Stop() { Console.WriteLine("Fan stopped"); } } //Concrete Commands public class LightOnCommand : ICommand { private Light _light; public LightOnCommand(Light light) { _light = light; } public void Execute() { _light.TurnOn(); } } public class LightOffCommand : ICommand { private Light _light; public LightOffCommand(Light light) { _light = light; } public void Execute() { _light.TurnOff(); } } public class FanStartCommand : ICommand { private Fan _fan; public FanStartCommand(Fan fan) { _fan = fan; } public void Execute() { _fan.Start(); } } public class FanStopCommand : ICommand { private Fan _fan; public FanStopCommand(Fan fan) { _fan = fan; } public void Execute() { _fan.Stop(); } } //Invoker - Voice Assistant public class VoiceAssistant { private ICommand _command; public void SetCommand(ICommand command) { _command = command; } public void HearVoiceCommand() { _command.Execute(); } } // Testing the Command Design Pattern // Client Code public class Program { public static void Main(string[] args) { Light livingRoomLight = new Light(); Fan bedroomFan = new Fan(); ICommand turnLightOn = new LightOnCommand(livingRoomLight); ICommand turnLightOff = new LightOffCommand(livingRoomLight); ICommand startFan = new FanStartCommand(bedroomFan); ICommand stopFan = new FanStopCommand(bedroomFan); VoiceAssistant assistant = new VoiceAssistant(); // User gives a voice command to turn on the light assistant.SetCommand(turnLightOn); assistant.HearVoiceCommand(); // User gives a voice command to start the fan assistant.SetCommand(startFan); assistant.HearVoiceCommand(); // User gives a voice command to turn off the light assistant.SetCommand(turnLightOff); assistant.HearVoiceCommand(); Console.ReadKey(); } } }
In this scenario, the Command pattern allows the system to easily add more devices or modify commands without affecting the existing structure. The Voice Assistant remains abstracted from the specific operations and invokes them. This abstraction provides scalability, making it simpler to integrate more complex commands or new devices in the future. When you run the above code, you will get the following output.
Real-Time Example of Command Design Pattern in C#: Simple Graphics Editor
In this graphics editor, users can draw circles and rectangles. Each drawing action is a command. The editor should also be able to undo and redo these drawing actions. Let us see how we can implement the above example using Command Design Pattern in C#:
using System; using System.Collections.Generic; using System.Linq; namespace CommandDesignPattern { //Command Interface public interface ICommand { void Execute(); void Undo(); } //Receiver - Graphics Editor Canvas public class Canvas { public void DrawCircle() { Console.WriteLine("Circle drawn"); } public void RemoveCircle() { Console.WriteLine("Circle removed"); } public void DrawRectangle() { Console.WriteLine("Rectangle drawn"); } public void RemoveRectangle() { Console.WriteLine("Rectangle removed"); } } //Concrete Commands public class DrawCircleCommand : ICommand { private Canvas _canvas; public DrawCircleCommand(Canvas canvas) { _canvas = canvas; } public void Execute() { _canvas.DrawCircle(); } public void Undo() { _canvas.RemoveCircle(); } } public class DrawRectangleCommand : ICommand { private Canvas _canvas; public DrawRectangleCommand(Canvas canvas) { _canvas = canvas; } public void Execute() { _canvas.DrawRectangle(); } public void Undo() { _canvas.RemoveRectangle(); } } //Invoker - Graphics Editor public class GraphicsEditor { private Stack<ICommand> _commandHistory = new Stack<ICommand>(); public void ExecuteCommand(ICommand command) { command.Execute(); _commandHistory.Push(command); } public void UndoLastCommand() { if (_commandHistory.Any()) { var lastCommand = _commandHistory.Pop(); lastCommand.Undo(); } } } // Testing the Command Design Pattern // Client Code public class Program { public static void Main(string[] args) { Canvas canvas = new Canvas(); GraphicsEditor editor = new GraphicsEditor(); ICommand drawCircle = new DrawCircleCommand(canvas); ICommand drawRectangle = new DrawRectangleCommand(canvas); editor.ExecuteCommand(drawCircle); editor.ExecuteCommand(drawRectangle); // Undo last action (Remove rectangle) editor.UndoLastCommand(); // Undo previous action (Remove circle) editor.UndoLastCommand(); Console.ReadKey(); } } }
In this example, the Command pattern offers a structured way to manage drawing and undoing actions in the graphics editor. The pattern allows for easy extensions, for example, adding more shapes or functionalities without disturbing the existing system. This modular approach simplifies maintenance and improves code readability. When you run the above code, you will get the following output.
Real-Time Example of Command Design Pattern in C#: Banking System
Let’s consider a banking system where customers can make deposits, withdrawals, and transfer funds. A customer can perform various actions on their bank account, like depositing, withdrawing, and transferring money to another account. Each of these actions can be treated as a command. Let us see how we can implement the above example using Command Design Pattern in C#:
using System; namespace CommandDesignPattern { //Command Interface public interface IBankCommand { void Execute(); } //Receiver - Bank Account public class BankAccount { public decimal Balance { get; private set; } public void Deposit(decimal amount) { Balance += amount; Console.WriteLine($"Deposited ${amount}. New balance: ${Balance}"); } public void Withdraw(decimal amount) { if (Balance >= amount) { Balance -= amount; Console.WriteLine($"Withdrew ${amount}. New balance: ${Balance}"); } else { Console.WriteLine("Insufficient funds."); } } public void Transfer(BankAccount toAccount, decimal amount) { if (Balance >= amount) { Balance -= amount; toAccount.Deposit(amount); Console.WriteLine($"Transferred ${amount} to another account. New balance: ${Balance}"); } else { Console.WriteLine("Insufficient funds for transfer."); } } } //Concrete Commands public class DepositCommand : IBankCommand { private BankAccount _account; private decimal _amount; public DepositCommand(BankAccount account, decimal amount) { _account = account; _amount = amount; } public void Execute() { _account.Deposit(_amount); } } public class WithdrawCommand : IBankCommand { private BankAccount _account; private decimal _amount; public WithdrawCommand(BankAccount account, decimal amount) { _account = account; _amount = amount; } public void Execute() { _account.Withdraw(_amount); } } public class TransferCommand : IBankCommand { private BankAccount _fromAccount; private BankAccount _toAccount; private decimal _amount; public TransferCommand(BankAccount fromAccount, BankAccount toAccount, decimal amount) { _fromAccount = fromAccount; _toAccount = toAccount; _amount = amount; } public void Execute() { _fromAccount.Transfer(_toAccount, _amount); } } //Invoker - Bank App public class BankApp { public void PerformOperation(IBankCommand command) { command.Execute(); } } // Testing the Command Design Pattern // Client Code public class Program { public static void Main(string[] args) { BankAccount johnsAccount = new BankAccount(); BankAccount janesAccount = new BankAccount(); BankApp bankApp = new BankApp(); bankApp.PerformOperation(new DepositCommand(johnsAccount, 500)); bankApp.PerformOperation(new WithdrawCommand(johnsAccount, 200)); bankApp.PerformOperation(new TransferCommand(johnsAccount, janesAccount, 150)); Console.ReadKey(); } } }
In this example, the Command pattern allows different banking operations to be decoupled from the bank application logic. This ensures that adding new banking operations or changing existing ones would be easy without making significant changes to the core application or the bank account classes. When you run the above code, you will get the following output.
Real-Time Example of Command Design Pattern in C#: Text Editor
Let’s consider a text editor where users can write, delete, copy, and paste text. In the text editor, various actions can be executed on the text. These actions can include writing some text, deleting a specific range of text, copying, and pasting. Each of these actions can be encapsulated as a command. Let us see how we can implement the above example using Command Design Pattern in C#:
using System; using System.Collections.Generic; using System.Text; namespace CommandDesignPattern { //Command Interface public interface ITextCommand { void Execute(); void Undo(); } //Receiver - TextDocument public class TextDocument { public StringBuilder Content { get; } = new StringBuilder(); public void Write(string text) { Content.Append(text); } public void Delete(int startIndex, int length) { Content.Remove(startIndex, length); } // Other methods for copy and paste can be added if needed } //Concrete Commands public class WriteCommand : ITextCommand { private TextDocument _document; private string _text; public WriteCommand(TextDocument document, string text) { _document = document; _text = text; } public void Execute() { _document.Write(_text); } public void Undo() { _document.Delete(_document.Content.Length - _text.Length, _text.Length); } } public class DeleteCommand : ITextCommand { private TextDocument _document; private string _deletedText; private int _startIndex; public DeleteCommand(TextDocument document, int startIndex, int length) { _document = document; _startIndex = startIndex; _deletedText = _document.Content.ToString().Substring(startIndex, length); } public void Execute() { _document.Delete(_startIndex, _deletedText.Length); } public void Undo() { _document.Content.Insert(_startIndex, _deletedText); } } //Invoker - TextEditor public class TextEditor { private Stack<ITextCommand> _commandHistory = new Stack<ITextCommand>(); public void ExecuteCommand(ITextCommand command) { command.Execute(); _commandHistory.Push(command); } public void UndoLastCommand() { if (_commandHistory.Count > 0) { var lastCommand = _commandHistory.Pop(); lastCommand.Undo(); } } } // Testing the Command Design Pattern // Client Code public class Program { public static void Main(string[] args) { TextDocument document = new TextDocument(); TextEditor editor = new TextEditor(); editor.ExecuteCommand(new WriteCommand(document, "Hello, world!")); Console.WriteLine(document.Content); // Outputs: Hello, world! editor.ExecuteCommand(new DeleteCommand(document, 7, 5)); Console.WriteLine(document.Content); // Outputs: Hello, ! editor.UndoLastCommand(); Console.WriteLine(document.Content); // Outputs: Hello, world! Console.ReadKey(); } } }
In this example, the Command pattern allows the text editor to encapsulate each operation as an object, making implementing features like undo and redo easy. If more operations (e.g., copy, paste) are needed in the future, new command classes can be added without altering the existing structure. When you run the above code, you will get the following output.
Real-Time Example of Command Design Pattern in C#: Music Player Application
In a music player application, users can perform several actions, such as playing a song, pausing the playback, and skipping to the next track. Each of these actions can be encapsulated as a command. Let us see how we can implement the above example using Command Design Pattern in C#:
using System; namespace CommandDesignPattern { //Command Interface public interface IMusicCommand { void Execute(); } //Receiver - MusicPlayer public class MusicPlayer { public void Play() { Console.WriteLine("Playing the song."); } public void Pause() { Console.WriteLine("Pausing the song."); } public void Skip() { Console.WriteLine("Skipping to the next song."); } } //Concrete Commands public class PlayCommand : IMusicCommand { private MusicPlayer _player; public PlayCommand(MusicPlayer player) { _player = player; } public void Execute() { _player.Play(); } } public class PauseCommand : IMusicCommand { private MusicPlayer _player; public PauseCommand(MusicPlayer player) { _player = player; } public void Execute() { _player.Pause(); } } public class SkipCommand : IMusicCommand { private MusicPlayer _player; public SkipCommand(MusicPlayer player) { _player = player; } public void Execute() { _player.Skip(); } } //Invoker - MusicRemote public class MusicRemote { private IMusicCommand _command; public void SetCommand(IMusicCommand command) { _command = command; } public void PressButton() { _command.Execute(); } } // Testing the Command Design Pattern // Client Code public class Program { public static void Main(string[] args) { // Receiver MusicPlayer player = new MusicPlayer(); // Invoker MusicRemote remote = new MusicRemote(); // Play song remote.SetCommand(new PlayCommand(player)); remote.PressButton(); // Pause playback remote.SetCommand(new PauseCommand(player)); remote.PressButton(); // Skip to next song remote.SetCommand(new SkipCommand(player)); remote.PressButton(); Console.ReadKey(); } } }
In this music player scenario, the Command pattern enables the decoupling of the invoker (MusicRemote) from the receiver (MusicPlayer). This makes adding new functionalities (like rewinding or adjusting volume) straightforwardly by introducing new command classes without altering the existing system structure. When you run the above code, you will get the following output.
Real-Time Example of Command Design Pattern in C#: E-Commerce Shopping Cart System
In an e-commerce shopping cart, users can add, remove, or update the quantity of products. Each of these operations can be encapsulated as a command. Let us see how we can implement the above example using Command Design Pattern in C#:
using System; namespace CommandDesignPattern { //Command Interface public interface ICartCommand { void Execute(); void Undo(); } //Receiver - ShoppingCart public class ShoppingCart { public void AddProduct(string productName) { Console.WriteLine($"Added {productName} to the cart."); } public void RemoveProduct(string productName) { Console.WriteLine($"Removed {productName} from the cart."); } public void UpdateQuantity(string productName, int quantity) { Console.WriteLine($"Updated {productName}'s quantity to {quantity}."); } } //Concrete Commands public class AddProductCommand : ICartCommand { private ShoppingCart _cart; private string _productName; public AddProductCommand(ShoppingCart cart, string productName) { _cart = cart; _productName = productName; } public void Execute() { _cart.AddProduct(_productName); } public void Undo() { _cart.RemoveProduct(_productName); } } public class RemoveProductCommand : ICartCommand { private ShoppingCart _cart; private string _productName; public RemoveProductCommand(ShoppingCart cart, string productName) { _cart = cart; _productName = productName; } public void Execute() { _cart.RemoveProduct(_productName); } public void Undo() { _cart.AddProduct(_productName); } } public class UpdateQuantityCommand : ICartCommand { private ShoppingCart _cart; private string _productName; private int _quantity; private int _previousQuantity; public UpdateQuantityCommand(ShoppingCart cart, string productName, int quantity, int previousQuantity) { _cart = cart; _productName = productName; _quantity = quantity; _previousQuantity = previousQuantity; } public void Execute() { _cart.UpdateQuantity(_productName, _quantity); } public void Undo() { _cart.UpdateQuantity(_productName, _previousQuantity); } } //Invoker - UserInterface public class UserInterface { private ICartCommand _command; public void SetCommand(ICartCommand command) { _command = command; } public void ExecuteAction() { _command.Execute(); } public void UndoAction() { _command.Undo(); } } // Testing the Command Design Pattern // Client Code public class Program { public static void Main(string[] args) { // Receiver ShoppingCart cart = new ShoppingCart(); // Invoker UserInterface ui = new UserInterface(); // User adds a product ui.SetCommand(new AddProductCommand(cart, "Laptop")); ui.ExecuteAction(); // User removes a product ui.SetCommand(new RemoveProductCommand(cart, "Laptop")); ui.ExecuteAction(); // User undoes the remove action ui.UndoAction(); Console.ReadKey(); } } }
In this e-commerce scenario, the Command pattern offers flexibility by allowing each shopping cart operation to be encapsulated in its own command class. This means that if more operations need to be added in the future (e.g., applying coupons or viewing the cart), new command classes can be introduced without affecting the existing structure. When you run the above code, you will get the following output.
In the next article, I will discuss the Visitor Design Pattern in C# with Examples. Here, in this article, I try to explain Real-Time Examples of Command Design Patterns in C#. I hope you enjoy this Real-Time Example of the Command Design Pattern using the C# article.