Команда (Command)
Шаблон Команда обеспечивает обработку команды в виде объекта, что позволяет сохранять её, передавать в качестве параметра методам, а также возвращать её в виде результата, как и любой другой объект.
Дизайн шаблона Команда показан на рис. 12. Все команды – это объекты классов, реализующих общий интерфейс или унаследованных от общего предка. Конкретная команда имеет некое состояние (контекст выполнения). Объект класса Receiver – это то, над чем выполняется команда. Команда изменяет состояние этого объекта. Класс Invoker инкапсулирует команду (или команды) и может выполнять команды по необходимости.
Рис. 12. Дизайн шаблона Команда.
Рассмотрим пример реализации шаблона Команда. Пусть класс Calculator обеспечивает выполнение арифметических операций с целыми числами.
// хранит целочисленное значение,
// производит с ним арифметические операции
public class Calculator
{
private int _value;
public void Operation(char @operator, int operand)
{
switch (@operator)
{
case '+':
_value += operand;
break;
case '-':
_value -= operand;
break;
case '*':
_value *= operand;
break;
case '/':
_value /= operand;
break;
}
Console.WriteLine("Current value = {0,1}", _value);
}
}
Интерфейс команды обеспечивает операции выполнения и отмены.
public interface ICommand
{
void Execute();
void Undo();
}
Создадим класс для описания команды.
public class CalculatorCommand : ICommand
{
private readonly Calculator _calculator;
private readonly char _operator;
private readonly int _operand;
public CalculatorCommand(Calculator calculator, char @operator,
int operand)
{
_calculator = calculator;
_operator = @operator;
_operand = operand;
}
public void Execute()
{
_calculator.Operation(_operator, _operand);
}
public void Undo()
{
_calculator.Operation(GetOppositeOperator(_operator),
_operand);
}
private static char GetOppositeOperator(char @operator)
{
const string operators = "+-*/";
const string opposite = "-+/*";
var pos = operators.IndexOf(@operator);
if (pos == -1)
{
throw new ArgumentException("@operator");
}
return opposite[pos];
}
}
Класс User поддерживает список команд для реализации функций отмены и повторного выполнения.
public class User
{
private readonly Calculator _calculator = new Calculator();
private readonly List<ICommand> _commands =
new List<ICommand>();
private int _current;
public void Compute(char @operator, int operand)
{
var command = new CalculatorCommand(_calculator, @operator,
operand);
command.Execute();
_commands.Add(command);
_current++;
}
public void Undo(int levels)
{
for (var i = 0; i < levels; i++)
{
if (_current > 0)
{
_commands[--_current].Undo();
}
}
}
public void Redo(int levels)
{
for (var i = 0; i < levels; i++)
{
if (_current < _commands.Count - 1)
{
_commands[_current++].Execute();
}
}
}
}
Использовать разработанные классы можно следующим образом:
// создаём объект для вычислений
var user = new User();
// выполняем несколько команд вычисления
user.Compute('+', 100);
user.Compute('-', 50);
user.Compute('*', 10);
user.Compute('/', 2);
// отменяем четыре команды
user.Undo(4);
// повторно выполняем три команды
user.Redo(3);