update on 5 min read
Command Design patterns
As a part of this article , I will explain about builder design pattern & what problem it solves?
Intro
The Command pattern allows you to represent operations as standalone objects. This gives your system flexibility, lets you manage requests in a uniform way, and enables powerful features like undo/redo, logging, and task scheduling—all while keeping the requesting code and the executing code independent of each other.
Core components in Command Design Pattern
- Command Interface: Declares an interface for all command classes. It usually has an execute() method.
- Concrete Command: Implements the Command interface and binds a receiver object to an action. It encapsulates the receiver object and invokes the corresponding operation on it when its execute() method is called.
- Receiver: An object that knows how to perform the actual operation. It is the target of the command.
- Invoker: An object that holds and asks the command to carry out the request. It doesn’t know anything about the concrete command or the receiver of the action. It simply has a way to execute the command.
- Client: Creates concrete command objects and sets their receiver.
Which Solid Priciple implemented in this Pattern?
- SRP is the primary SOLID principle here — each class has a single, well-defined responsibility.
- OCP is a natural side effect — you can extend behavior by adding new commands without touching existing code.
Real-World Analogy
- A customer comes to hotel and try to give an order
- The waiter (invoker) takes your order ( command object) and pass to kitchen (receiver)
- The waiter doesn’t know about how the chief cooks
- The order can be queued, modified, cancelled or repeated with outchanges the waiter process
UML Diagram

Simple Command Pattern
Purpose
This solution implements a command-based banking system where financial transactions (deposits and withdrawals) on an account can be executed, tracked, and reversed in a reliable and structured manner. The design uses the Command Pattern to encapsulate transaction logic, enabling features like undo/redo, transaction grouping, and auditability.
Core Business Rules and Logic
1. Account Management
Object:
Account
Responsibilities:
- Maintains the account balance and applies an overdraft limit for withdrawals.
- Provides methods for depositing funds (increasing balance) and withdrawing funds (reducing balance), with validation against the overdraft policy.
- Exposes current balance for display or auditing purposes.
Business Rule Details:
- Any deposit directly increases the balance. Deposit:
- A withdrawal only succeeds if the resulting balance does not violate the overdraft limit. Withdraw:
- Balance Visibility: The current balance is accessible (read-only) at any time for reporting.
2. Transaction Encapsulation (Command Pattern)
Components: ,
ICommand``BankAccountCommand
Responsibilities:
- Encapsulates each banking operation (deposit or withdrawal) in a separate command object.
- Each command knows how to execute its operation and how to undo it—enabling features like transaction reversal.
- Records the execution state of each command for reliable undo/redo operations.
- Encapsulates each banking operation (deposit or withdrawal) in a separate command object.
Business Rule Details:
- Command Creation: Each operation (either deposit or withdraw) is wrapped within a command that stores the type of action, the target account, and the transaction amount.
- Execution: Calling on a command performs the transaction on the account.
Execute
- Undo: Calling on the command reverses the performed action (withdraw undoes a deposit and vice versa), only if the command was executed successfully.
Undo
- Execution: Calling on a command performs the transaction on the account.
- Command Creation: Each operation (either deposit or withdraw) is wrapped within a command that stores the type of action, the target account, and the transaction amount.
3. Batch Processing and Transaction History
Component: Main program logic ()
Program.cs
Responsibilities:
- Creates a series of commands representing a batch of transactions.
- Executes all transactions sequentially.
- Allows transactions to be reversed (undone) in reverse order, preserving the integrity of the account’s state.
- Creates a series of commands representing a batch of transactions.
Business Rule Details:
- Batch Execution: All commands in a list are executed on a single account, updating the balance step by step.
- Undo Mechanism: By reversing through the command history and calling , all transactions can be rolled back to their original state, supporting audit trails and error correction.
Undo
- Undo Mechanism: By reversing through the command history and calling , all transactions can be rolled back to their original state, supporting audit trails and error correction.
- Batch Execution: All commands in a list are executed on a single account, updating the balance step by step.
Code Explaination
Command Interface
- Component: interface (in ICommand.cs)
ICommand
- Role: Declares the contract for command objects ( and methods).
Execute``Undo
public interface ICommand { void Execute(); void Undo(); }
Concrete Command
- Component: class (in ICommand.cs)
BankAccountCommand
- Role: Implements the interface, encapsulating a request to perform deposit or withdrawal on an account.
ICommand
public class BankAccountCommand : ICommand{ private readonly Account _account; private readonly ActionType _actionType; private readonly int _amount; private bool _isExecuted;
public enum ActionType { Deposit, Withdraw }
public BankAccountCommand(Account account, ActionType actionType, int amount) { _account = account; _actionType = actionType; _amount = amount; } public void Execute() { switch (_actionType) { case ActionType.Deposit: _account.Deposit(_amount); _isExecuted=true; break;
case ActionType.Withdraw: _isExecuted=_account.Withdraw(_amount); break;
default: break; } }
public void Undo() { if (!_isExecuted) return; switch (_actionType) { case ActionType.Deposit: _isExecuted= _account.Withdraw(_amount); break; case ActionType.Withdraw: _account.Deposit(_amount); _isExecuted=true; break; default: break; } }}
Receiver
- Component: class (in Account.cs)
Account
- Role: Performs the actual business logic: deposit and withdraw money. The command delegates the actual work to this receiver.
public class Account{ private int _balance; private readonly int _overdDraftLimit;
public void Deposit(int amount) { _balance += amount; WriteLine($"Deposit amount ${amount} "); WriteLine($"Balance is ${_balance}"); }
public bool Withdraw(int amount) { if (_balance - _overdDraftLimit < amount) return false; _balance -= amount; WriteLine($"Withdraw amount ${amount}"); WriteLine($"Balance is ${_balance}"); return true; }
public int GetBalance => _balance;}
Invoker
- Component: The code in
Program
class that loops through the list of commands and invokes and (in Program.cs)Execute()``Undo()
- Role: Initiates execution or reversal of commands without knowing their details.
foreach (var cmd in command) { cmd.Execute(); }
Client
- Component: The code in
Main
method that creates the , instantiates the objects, and prepares the list of commands (in Program.cs)Account``BankAccountCommand
- Role: Sets up everything: creates the commands, sets up the receiver (account), and hands over the commands to the invoker logic.
internal static class Program{ private static void Main(string[] args) { var account = new Account(); var command = new List<BankAccountCommand> { new BankAccountCommand(account, BankAccountCommand.ActionType.Deposit, 100), new BankAccountCommand(account, BankAccountCommand.ActionType.Withdraw, 500), }; WriteLine(account.GetBalance);
foreach (var cmd in command) { cmd.Execute(); } WriteLine(account.GetBalance);
WriteLine("Reverse order"); foreach (var cmd in Enumerable.Reverse(command)) { cmd.Undo(); } WriteLine(account.GetBalance); }}