Существуют ситуации, когда у нас есть просто данные, над которыми нужно провести одну лишь единственную операцию, например, у нас есть кино на DVD диске и нам нужно всего лишь либо, запустить фильм, либо остановить, либо нажать на паузу и так далее. Также нам может понадобится такое действие, которое может отменить предыдущее (например операция undo в блокноте). Я могу написать функции (или методы), которые будут исполнять нашу команду и обрабатывать ее, но у нас будет очень много похожего кода, так как у нас не будет базового класса, который будет иметь поля схожие для всех команд. К тому же код будет очень не гибким. Фактически это КЛАСС, который инкапсулирует один единственный метод execute(). Это позволяет нам хранить команды в каких то контейнерах, обрабатывать их с помощью наших обработчиков.
(Пример стыбзен с википедии). Мы проектируем калькулятор со стандартными операциями сложения, деления, умножения, вычитания
Все строится сначала на классе Command:
(Пример стыбзен с википедии). Мы проектируем калькулятор со стандартными операциями сложения, деления, умножения, вычитания
Все строится сначала на классе Command:
abstract class Command
{
public abstract void Execute(); //метод выполнения команды
public abstract void UnExecute(); //метод отмены
}
class CalculatorCommand : Command
{
char @operator; //оператор
int operand;
Calculator calculator; //ОБЪЕКТ ПОЛУЧАЮЩИЙ КОМАНДЫ (Receiver)
// Constructor
public CalculatorCommand(Calculator calculator,
char @operator, int operand)
{
this.calculator = calculator;
this.@operator = @operator;
this.operand = operand;
}
public char Operator
{
set{ @operator = value; }
}
public int Operand
{
set{ operand = value; }
}
//здесь мы просто вызываем метод нашего получателя, на вход которого мы отправляем оператор и операнд
public override void Execute()
{
calculator.Operation(@operator, operand);
}
public override void UnExecute()
{
calculator.Operation(Undo(@operator), operand);
}
// Private helper function : приватные вспомогательные функции
private char Undo(char @operator)
{
char undo;
switch(@operator)
{
case '+': undo = '-'; break;
case '-': undo = '+'; break;
case '*': undo = '/'; break;
case '/': undo = '*'; break;
default : undo = ' '; break;
}
return undo;
}
}
Теперь нужен класс который будет получать команды и их обрабатывать.
// "Receiver" : получатель
class Calculator
{
private int curr = 0;
public void Operation(char @operator, int operand)
{
switch(@operator)
{
case '+': curr += operand; break;
case '-': curr -= operand; break;
case '*': curr *= operand; break;
case '/': curr /= operand; break;
}
Console.WriteLine(
"Current value = {0,3} (following {1} {2})",
curr, @operator, operand);
}
}
class User
{
// Initializers
private Calculator _calculator = new Calculator();
private List _commands = new List ();
private int _current = 0;
public void Redo(int levels)
{
Console.WriteLine("\n---- Redo {0} levels ", levels);
// Делаем возврат операций
for (int i = 0; i < levels; i++)
if (_current < _commands.Count - 1)
_commands[_current++].Execute();
}
public void Undo(int levels)
{
Console.WriteLine("\n---- Undo {0} levels ", levels);
// Делаем отмену операций
for (int i = 0; i < levels; i++)
if (_current > 0)
_commands[--_current].UnExecute();
}
public void Compute(char @operator, int operand)
{
// Создаем команду операции и выполняем её
Command command = new CalculatorCommand(
_calculator, @operator, operand);
command.Execute();
// Добавляем операцию к списку отмены
_commands.Add(command);
_current++;
}
}
Ну и пример работы с нашим калькулятором
class MainApp
{
static void Main()
{
// Создаем пользователя.
User user = new User();
// Пусть он что-нибудь сделает.
user.Compute('+', 100);
user.Compute('-', 50);
user.Compute('*', 10);
user.Compute('/', 2);
// Отменяем 4 команды
user.Undo(4);
// Вернём 3 отменённые команды.
user.Redo(3);
// Ждем ввода пользователя и завершаемся.
Console.Read();
}
}
Итак, теперь обобщим все, что мы здесь написали, вот схемка шаблона:
Ну, кто не силен в английском, могу объяснить, сначала наш вызывающий (по английски Invoker) (в нашем случае User), вызывает команду (причем команда передается в виде объекта) и посылает ее получателю (Calculator), где команда успешно обрабатывается калькулятором.
Благодаря такому шаблону, мы можем без труда можем добавить свои команды, которые с помощью метода execute() будут также выполнятся. Всего лишь надо унаследовать все от Command.