Команда (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);