Introduction:
Command Design Pattern enables you to encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
Example:
The below code demonstrates the Command pattern to be used on a simple calculator. This caluclator doing unlimited number of undo’s & Redo’s .
One thing we might do to extend this Calculator project, is to create an IOperator Interface and for each operation have a concret Operator Class. for simplicity I am not going to do this. I will hard code couple of operator to make it very simple to be understood.
static void Main() { // Create user and let her compute User user = new User(); // User presses calculator buttons user.Calculate(‘+’, 100); user.Calculate(‘-‘, 50); user.Calculate(‘*’, 10); user.Calculate(‘/’, 2); // Undo 4 commands user.UndoCalculation(4); // Redo 3 commands user.RedoCalculation(3); // Wait for user Console.ReadKey(); } interface ICommand { void Execute(); void UnExecute(); } class CalculationCommand : ICommand { private char _operator; private int _operand; private Calculator _calculator; // Constructor public CalculationCommand(Calculator calculator, char @operator, int operand) { this._calculator = calculator; this._operator = @operator; this._operand = operand; } // Gets operator public char Operator { set { _operator = value; } } // Get operand public int Operand { set { _operand = value; } } // Execute new command publicĀ void Execute() { _calculator.Operation(_operator, _operand); } // Unexecute last command publicĀ void UnExecute() { _calculator.Operation(Undo(_operator), _operand); } // Returns opposite operator for given operator private char Undo(char @operator) { switch (@operator) { case ‘+’: return ‘-‘; case ‘-‘: return ‘+’; case ‘*’: return ‘/’; case ‘/’: return ‘*’; default: throw new ArgumentException(“@operator”); } } } class Calculator { private int _currentIndex = 0; public void Operation(char @operator, int operand) { switch (@operator) { case ‘+’: _currentIndex += operand; break; case ‘-‘: _currentIndex -= operand; break; case ‘*’: _currentIndex *= operand; break; case ‘/’: _currentIndex /= operand; break; } Console.WriteLine( “Current value = {0,3} (following {1} {2})”, _currentIndex, @operator, operand); } } class User { // Initializers private Calculator _calculator = new Calculator(); private List<ICommand> _commands = new List<ICommand>(); private int _currentIndex = 0; public void RedoCalculation(int levels) { Console.WriteLine(“\n—- Redo {0} levels “, levels); // Perform redo operations for (int i = 0; i < levels; i++) { if (_currentIndex < _commands.Count – 1) { ICommand command = _commands[_currentIndex++]; command.Execute(); } } } public void UndoCalculation(int levels) { Console.WriteLine(“\n—- Undo {0} levels “, levels); // Perform undo operations for (int i = 0; i < levels; i++) { if (_currentIndex > 0) { ICommand command = _commands[–_currentIndex] as ICommand; command.UnExecute(); } } } public void Calculate(char @operator, int operand) { // Create command operation and execute it ICommand command = new CalculationCommand( _calculator, @operator, operand); command.Execute(); // Add command to undo list _commands.Add(command); _currentIndex++; } } |