Введение
В объектно-ориентированном программировании, шаблон "Команда" – это поведенческий шаблон проектирования, в котором объект используется для инкапсуляции всей информации, необходимой для выполнения действия или запуска события в последующее время. Эта информация включает имя метода, объект, которому принадлежит метод, и значения параметров метода. Четыре термина, всегда связанные с шаблоном "Команда", – это команда, получатель, инициатор и клиент. Объект команды знает о получателе и вызывает метод получателя. Значения параметров метода получателя хранятся в команде. Объект получателя, необходимый для выполнения этих методов, также хранится в объекте команды посредством агрегации. Получатель выполняет работу при вызове метода "выполнить" в команде. Объект инициатора знает, как выполнить команду, и может вести учет выполнения команды. Инициатор не знает ничего о конкретной команде, он знает только об интерфейсе команды. Объекты инициатора, объекты команд и объекты получателей хранятся клиентским объектом; клиент решает, какие объекты получателей он назначает объектам команд, а какие команды назначает инициатору. Клиент определяет, какие команды выполнять и в какие моменты времени. Для выполнения команды клиент передает объект команды объекту инициатора. Использование объектов команд упрощает создание общих компонентов, которым необходимо делегировать, последовательно выполнять или выполнять вызовы методов в выбранный ими момент, без необходимости знать класс метода или параметры метода. Использование объекта инициатора позволяет удобно вести учет выполнения команд, а также реализовывать различные режимы для команд, управляемые объектом инициатора, без необходимости информировать клиента о существовании учета или режимов. Основные идеи этого шаблона проектирования тесно соответствуют семантике функций первого класса и функций высшего порядка в функциональных языках программирования. В частности, объект инициатора является функцией высшего порядка, в которой объект команды выступает аргументом первого класса.
In object oriented programming, the command pattern is a behavioral design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time. This information includes the method name, the object that owns the method and values for the method parameters. Four terms always associated with the command pattern are command, receiver, invoker and client. A command object knows about receiver and invokes a method of the receiver. Values for parameters of the receiver method are stored in the command. The receiver object to execute these methods is also stored in the command object by aggregation. The receiver then does the work when the execute method in command is called. An invoker object knows how to execute a command, and optionally does bookkeeping about the command execution. The invoker does not know anything about a concrete command, it knows only about the command interface. Invoker object(s), command objects and receiver objects are held by a client object, the client decides which receiver objects it assigns to the command objects, and which commands it assigns to the invoker. The client decides which commands to execute at which points. To execute a command, it passes the command object to the invoker object. Using command objects makes it easier to construct general components that need to delegate, sequence or execute method calls at a time of their choosing without the need to know the class of the method or the method parameters. Using an invoker object allows bookkeeping about command executions to be conveniently performed, as well as implementing different modes for commands, which are managed by the invoker object, without the need for the client to be aware of the existence of bookkeeping or modes. The central ideas of this design pattern closely mirror the semantics of first class functions and higher order functions in functional programming languages. Specifically, the invoker object is a higher order function of which the command object is a first class argument.
Терминология
Терминология, используемая для описания реализации паттерна команд, непоследовательна и поэтому может вводить в заблуждение. Это результат неоднозначности, использования синонимов и реализаций, которые могут исказить первоначальный паттерн, значительно выходя за его рамки. Неоднозначность. Термин "команда" неоднозначен. Например, "переместить вверх, переместить вверх" может относиться к одной команде ("переместить вверх"), которая должна быть выполнена дважды, или к двум командам, каждая из которых выполняет одно и то же действие ("переместить вверх"). Если первая команда добавляется дважды в стек отмены, оба элемента стека ссылаются на один и тот же экземпляр команды. Это уместно, когда команду всегда можно отменить одним и тем же способом (например, "переместить вниз"). И "Банда Четверых", и пример на Java используют эту интерпретацию термина "команда". С другой стороны, если в стек отмены добавлены последние команды, стек ссылается на два отдельных объекта. Это уместно, когда каждый объект в стеке должен содержать информацию, позволяющую отменить команду. Например, для отмены команды "удалить выделение" объект может содержать копию удаленного текста, чтобы его можно было повторно вставить, если команду "удалить выделение" необходимо отменить. Следует отметить, что использование отдельного объекта для каждого вызова команды также является примером паттерна "цепочка ответственности". Термин "выполнить" также неоднозначен. Он может относиться к запуску кода, идентифицированного методом "выполнить" объекта команды. Однако в Microsoft Windows Presentation Foundation (WPF) команда считается выполненной, когда был вызван метод "выполнить" команды, но это не обязательно означает, что код приложения был запущен. Это происходит только после дальнейшей обработки событий. Синонимы и омонимы. Клиент, Источник, Инициатор: кнопка, кнопка панели инструментов или пункт меню, нажатый пользователем, клавиша-сочетание. Командный объект, Маршрутизируемый командный объект, Объект действия: одиночный объект (например, существует только один объект CopyCommand), который знает о клавишах-сочетаниях, изображениях кнопок, тексте команд и т. д., связанных с командой. Объект-источник или объект-инициатор вызывает метод "выполнить" или "performAction" объекта "Команда" или "Действие". Объект "Команда/Действие" уведомляет соответствующие объекты-источники/инициаторы об изменении доступности команды/действия. Это позволяет кнопкам и пунктам меню становиться неактивными (затененными), когда команда/действие не может быть выполнено/выполнено. Приемник, Целевой объект: объект, который собираются копировать, вставлять, перемещать и т. д. Объект-приемник владеет методом, который вызывается методом "выполнить" команды. Приемник обычно также является целевым объектом. Например, если объект-приемник — курсор, а метод называется "moveUp", то можно ожидать, что курсор является целью действия "moveUp". С другой стороны, если код определен самим объектом команды, то целевым объектом будет совершенно другой объект. Командный объект, аргументы маршрутизируемого события, объект события: объект, который передается от источника к объекту "Команда/Действие", к объекту-цели и коду, выполняющему работу. Каждое нажатие кнопки или клавиши-сочетания приводит к созданию нового объекта команды/события. Некоторые реализации добавляют больше информации к объекту команды/события по мере его передачи от одного объекта (например, CopyCommand) к другому (например, разделу документа). Другие реализации помещают объекты команд/событий в другие объекты событий (как коробку внутри большей коробки) по мере их перемещения по цепочке, чтобы избежать конфликтов имен. (См. также паттерн "цепочка ответственности".) Обработчик, ExecutedRoutedEventHandler, метод, функция: фактический код, выполняющий копирование, вставку, перемещение и т. д. В некоторых реализациях код обработчика является частью объекта "Команда/Действие". В других реализациях код является частью объекта "Приемник/Цель", а в третьих реализациях код обработчика отделен от других объектов. Диспетчер команд, Диспетчер отмены, Планировщик, Очередь, Диспетчер, Инициатор: объект, который помещает объекты команд/событий в стек отмены или стек повтора, или который удерживает объекты команд/событий до тех пор, пока другие объекты не будут готовы к действию, или который направляет объекты команд/событий к соответствующему объекту-приемнику/цели или коду обработчика. Реализации, значительно выходящие за рамки первоначального паттерна команд. Microsoft Windows Presentation Foundation (WPF) представляет маршрутизируемые команды, которые объединяют паттерн команд с обработкой событий. В результате объект команды больше не содержит ссылку на целевой объект и ссылку на код приложения. Вместо этого вызов метода "выполнить" объекта команды приводит к так называемому "Маршрутизируемому событию выполнения", которое в процессе туннелирования или всплытия может встретить так называемый "связывающий объект", который определяет целевой объект и код приложения, который выполняется в этот момент.
История
Первое опубликованное упоминание об использовании класса Command для реализации интерактивных систем, по-видимому, содержится в статье Генри Либермана 1985 года. Первое опубликованное описание механизма отмены и повторного выполнения (многоуровневого типа), использующего класс Command с методами execute и undo, а также список истории, встречается в первом (1988) издании книги Бертрана Мейера «Объектно-ориентированное построение программного обеспечения», в разделе 12.2.