Команда — это поведенческий паттерн проектирования, который превращает запросы в объекты, позволяя передавать их как аргументы при вызове методов, ставить запросы в очередь, логировать их, а также поддерживать отмену операций.
Команда является поведенческим шаблоном, в котором объект используется для инкапсуляции всей информации, необходимой для выполнения действия или вызова события в более позднее время. Эта информация включает в себя имя метода, объект, который является владельцем метода и значения параметров метода.
Четыре термина всегда связаны с шаблоном Команда: команды (command), приёмник команд (receiver), вызывающий команды (invoker) и клиент (client). Объект Command знает о приёмнике и вызывает метод приемника. Значения параметров приёмника сохраняются в команде. Вызывающий объект (invoker) знает, как выполнить команду и, возможно, делает учёт и запись выполненных команд. Вызывающий объект (invoker) ничего не знает о конкретной команде, он знает только об интерфейсе. Оба объекта (вызывающий объект и несколько объектов команд) принадлежат объекту клиента (client). Клиент решает, какие команды выполнить и когда. Чтобы выполнить команду он передает объект команды вызывающему объекту (invoker).
Использование командных объектов упрощает построение общих компонентов, которые необходимо делегировать или выполнять вызовы методов в любое время без необходимости знать методы класса или параметров метода. Использование вызывающего объекта (invoker) позволяет ввести учёт выполненных команд без необходимости знать клиенту об этой модели учёта (такой учёт может пригодиться, например, для реализации отмены и повтора команд).
Пример на PHP
/** * Абстрактый класс "команды" * @abstract */ abstract class Command { public abstract function Execute(); public abstract function UnExecute(); } /** * Класс конкретной "команды" */ class CalculatorCommand extends Command { /** * Текущая операция команды * * @var string */ public $operator; /** * Текущий операнд * * @var mixed */ public $operand; /** * Класс, для которого предназначена команда * * @var object of class Calculator */ public $calculator; /** * Конструктор * * @param object $calculator * @param string $operator * @param mixed $operand */ public function __construct($calculator, $operator, $operand) { $this->calculator = $calculator; $this->operator = $operator; $this->operand = $operand; } /** * Переопределенная функция parent::Execute() */ public function Execute() { $this->calculator->Operation($this->operator, $this->operand); } /** * Переопределенная функция parent::UnExecute() */ public function UnExecute() { $this->calculator->Operation($this->Undo($this->operator), $this->operand); } /** * Какое действие нужно отменить? * * @private * @param string $operator * @return string */ private function Undo($operator) { //каждому произведенному действию найти обратное switch($operator) { case '+': $undo = '-'; break; case '-': $undo = '+'; break; case '*': $undo = '/'; break; case '/': $undo = '*'; break; default : $undo = ' '; break; } return $undo; } } /** * Класс получатель и исполнитель "команд" */ class Calculator { /** * Текущий результат выполнения команд * * @private * @var int */ private $curr = 0; public function Operation($operator,$operand) { //выбрать оператора для вычисления результата switch($operator) { case '+': $this->curr+=$operand; break; case '-': $this->curr-=$operand; break; case '*': $this->curr*=$operand; break; case '/': $this->curr/=$operand; break; } print("Текущий результат = $this->curr (после выполнения $operator c $operand)"); } } /** * Класс, вызывающий команды */ class User { /** * Этот класс будет получать команды на исполнение * * @private * @var object of class Calculator */ private $calculator; /** * Массив операций * * @private * @var array */ private $commands = array(); /** * Текущая команда в массиве операций * * @private * @var int */ private $current = 0; public function __construct() { //создать экземпляр класса, который будет исполнять команды $this->calculator = new Calculator(); } /** * Функция возврата отмененных команд * * @param int $levels количество возвращаемых операций */ public function Redo($levels) { print("\n---- Повторить $levels операций "); // Делаем возврат операций for ($i = 0; $i < $levels; $i++) if ($this->current < count($this->commands) - 1) $this->commands[$this->current++]->Execute(); } /** * Функция отмены команд * * @param int $levels количество отменяемых операций */ public function Undo($levels) { print("\n---- Отменить $levels операций "); // Делаем отмену операций for ($i = 0; $i < $levels; $i++) if ($this->current > 0) $this->commands[--$this->current]->UnExecute(); } /** * Функция выполнения команд * * @param string $operator * @param mixed $operand */ public function Compute($operator, $operand) { // Создаем команду операции и выполняем её $command = new CalculatorCommand($this->calculator, $operator, $operand); $command->Execute(); // Добавляем операцию к массиву операций и увеличиваем счетчик текущей операции $this->commands[]=$command; $this->current++; } } $user = new User(); // Произвольные команды $user->Compute('+', 100); $user->Compute('-', 50); $user->Compute('*', 10); $user->Compute('/', 2); // Отменяем 4 команды $user->Undo(4); // Вернём 3 отменённые команды. $user->Redo(3);