Команда (Command)
реализации: java, количество: 5
реализации(исходники)
+добавить
Команда- паттерн поведения объектов, инкапсулирующий различные алгоритмы в единую сущность. Встречается также под именами Action (действие), Transaction (транзакция). codelab.ru оригинал источник codelab.ru
Условия, Задача, Назначение
Инкапсулирует запрос на выполнение конкретной логики (алгоритма) – в виде объекта, позволяя тем самым задавать параметры клиентов для обработки соответствующих запросов, ставить запросы в очередь или протоколировать их, а также поддерживать отмену операций.
Мотивация
Иногда необходимо посылать объектам запросы, ничего не зная о том, выполнение какой операции запрошено и кто является получателем, в смысле кто будет ее исполнять. Например, в библиотеках для построения пользовательских интерфейсов встречаются такие объекты, как кнопки и меню, которые посылают запрос в ответ на действие пользователя. оригинал источник codelab.ru codelab.ru
источник оригинал codelab.ru codelab.ru
оригинал источник codelab.ru codelab.ru
источник оригинал codelab.ru codelab.ru
codelab.ru источник codelab.ru оригинал
Признаки применения, использования паттерна Команда (Command)
Используйте паттерн команда, когда хотите: оригинал источник codelab.ru codelab.ru- Параметризовать объекты выполняемым действием.
Как в случае с пунктами меню Menultem. В процедурном языке такую параметризацию можно выразить с помощью функции обратного вызова, то есть такой функции, которая регистрируется (динамически компонуется и создается таким образом в приложении), чтобы быть вызванной позднее. Команды представляют собой объектно-ориентированную альтернативу функциям обратного вызова. codelab.ru источник оригинал codelab.ru - Определять, ставить в очередь и выполнять запросы в разное время.
Время жизни объекта Command необязательно должно зависеть от времени жизни исходного запроса. Если получателя запроса удается реализовать так, чтобы он не зависел от адресного пространства, то объект-команду можно передать другому процессу, который займется его выполнением. Либо реализовать так что получатель не будет зависеть также от runtime-среды выполнения (виртуальной машины или сервера например) – то объект команду вполне можно сериализовать передать по какому-либо протоколу, далее десериализовать и выполнить уже на удаленном конце другим получателем. оригинал codelab.ru codelab.ru источник - Поддержать отмену операций.
Операция Execute объекта Command может сохранить состояние, необходимое для отката действий, выполненных командой. В этом случае в интерфейсе класса Command должна быть дополнительная операция Unexecute, которая отменяет действия, выполненные предшествующим обращением к Execute. Выполненные команды хранятся в списке истории. Для реализации произвольного числа уровней отмены и повтора команд нужно обходить этот список соответственно в обратном и прямом направлениях, вызывая при посещении каждого элемента команду Unexecute или Execute. оригинал codelab.ru источник codelab.ru - Поддержать протоколирование изменений (лог).
Чтобы их можно было выполнить повторно после аварийной остановки системы. Дополнив интерфейс класса Command операциями сохранения и загрузки, вы сможете вести протокол изменений во внешней памяти. Для восстановления после сбоя нужно будет загрузить сохраненные команды с диска и повторно выполнить их с помощью операции Execute. источник codelab.ru codelab.ru оригинал - Структурировать систему на основе высокоуровневых операций, построенных из примитивных.
Такая структура типична для информационных систем, поддерживающих транзакции. Транзакция инкапсулирует целый набор изменений данных. паттерн команда позволяет моделировать транзакции. У всех команд есть общий интерфейс, что дает возможность работать одинаково с любыми транзакциями. С помощью этого паттерна можно легко добавлять в систему новые виды транзакций. codelab.ru codelab.ru источник оригинал
Решение
источник оригинал codelab.ru codelab.ru
источник codelab.ru codelab.ru оригинал
Участники паттерна Команда (Command)
codelab.ru оригинал codelab.ru источник- Command – команда.
Объявляет интерфейс для выполнения операций. источник оригинал codelab.ru codelab.ru - ConcreteCommand (PasteCommand, OpenCommand) - конкретная команда.
Определяет связь между объектом-получателем Receiver и действием.
Реализует операцию Execute путем вызова соответствующих операций объекта Receiver; оригинал источник codelab.ru codelab.ru - Client (Application) – клиент.
Создает объекты класса ConcreteCommand и устанавливает их получателей. источник оригинал codelab.ru codelab.ru - Invoker (Menultem) – инициатор.
Обращается к команде для выполнения запроса. источник codelab.ru codelab.ru оригинал - Receiver (Document, Application) – получатель.
Располагает информацией о способах выполнения операций, необходимых для удовлетворения запроса. В роли получателя может выступать любой класс. источник оригинал codelab.ru codelab.ru
Схема использования паттерна Команда (Command)
Клиент создает объект ConcreteCommand и устанавливает для него получателя. Инициатор Invoker сохраняет объект ConcreteCommand. После когда запрашивается данная команда, инициатор отправляет запрос, вызывая операцию команды Execute. Если codelab.ru codelab.ru оригинал источникНа следующей диаграмме видно, как Command разрывает связь между инициатором и получателем (а также запросом, который должен выполнить последний): источник оригинал codelab.ru codelab.ru
codelab.ru оригинал источник codelab.ru
Вопросы, касающиеся реализации паттерна Команда (Command)
При реализации следует обратить внимание на следующие моменты: оригинал источник codelab.ru codelab.ru- Насколько «умной» должна быть команда.
У команды может быть широкий круг обязанностей. На одном полюсе стоит простое определение связи между получателем и действиями, которые нужно выполнить для удовлетворения запроса. На другом – независимая команда, т.е. реализация всего самостоятельно, без обращения за помощью к получателю. Последний вариант полезен, когда вы хотите определить команды, не зависящие от существующих классов, когда подходящего получателя не существует или когда получатель команде точно не известен. Например, команда, создающая новое окно приложения, может не понимать, что именно она создает, а трактовать окно, как любой другой объект. Где-то посередине между двумя крайностями находятся команды, обладающие достаточной информацией для динамического обнаружения своего получателя. оригинал источник codelab.ru codelab.ru - Поддержка отмены и повтора операций.
Команды могут поддерживать отмену и повтор операций, если имеется возможность отменить результаты выполнения (например, операцию Unexecute или Undo). В классе ConcreteCommand может сохраняться необходимая для этого дополнительная информация, в том числе:
- объект-получатель Receiver, который выполняет операции в ответ на запрос;
- аргументы операции, выполненной получателем;
- исходные значения различных атрибутов получателя, которые могли измениться в результате обработки запроса.
Получатель должен предоставить операции, позволяющие команде вернуться в исходное состояние. Для поддержки всего одного уровня отмены приложению достаточно сохранять только последнюю выполненную команду. Если же нужны многоуровневые отмена и повтор операций, то придется вести список истории выполненных команд. Максимальная длина этого списка и определяет число уровней отмены и повтора. Проход по списку в обратном направлении и откат результатов всех встретившихся по пути команд отменяет их действие.
Проход в прямом направлении и выполнение встретившихся команд приводит к повтору выполнения действий.
Команду, допускающую отмену, возможно, придется клонировать (побайтно) перед помещением в список истории. Дело в том, что объект команды, использованный для доставки запроса, скажем от пункта меню MenuItem, позже мог быть использован для других запросов. Поэтому копирование необходимо, чтобы определить разные вызовы одной и той же команды, если ее состояние при любом вызове может изменяться.
Например, команда DeleteCoinmand, которая удаляет выбранные объекты, при каждом вызове должна сохранять разные наборы объектов. Поэтому объект DeleteCommand необходимо скопировать после выполнения, а копию поместить в список истории. Если в результате выполнения состояние команды никогда не изменяется, то копировать не нужно - в список достаточно поместить лишь ссылку на команду. Команды, которые обязательно нужно копировать перед помещением в список истории, ведут себя подобно прототипам. codelab.ru источник codelab.ru оригинал - Накопление ошибок в процессе отмены.
При обеспечении надежного, сохраняющего семантику механизма отмены и повтора может возникнуть проблема гистерезиса. При выполнении, отмене и повторе команд иногда накапливаются ошибки, в результате чего состояние приложения оказывается отличным от первоначального. Поэтому порой необходимо сохранять в команде больше информации, дабы гарантировать, что объекты будут целиком восстановлены. Чтобы предоставить команде доступ к этой информации, не раскрывая внутреннего устройства объектов, можно воспользоваться паттерном хранитель. источник оригинал codelab.ru codelab.ru - Применение шаблонов в C++.
Для команд, которые не допускают отмену и не имеют аргументов, в языке C++ можно воспользоваться шаблонами, чтобы не создавать подкласс класса Command для каждой пары действие-получатель. codelab.ru источник оригинал codelab.ru
- Команда разрывает связь между объектом, инициирующим операцию, и объектом, имеющим информацию о том, как ее выполнить. оригинал источник codelab.ru codelab.ru
- Команды - это самые настоящие объекты.
Допускается манипулировать ими и расширять их точно так же, как в случае с любыми другими объектами, наследовать, компоновать, агрегировать для получения новых команд или модификации имеющихся. источник оригинал codelab.ru codelab.ru - Из простых команд можно собирать составные.
Например, класс MacroCommand, рассмотренный выше. В общем случае составные команды описываются паттерном компоновщик. codelab.ru оригинал codelab.ru источник - Добавлять новые команды легко.
Поскольку никакие существующие классы изменять не нужно. источник оригинал codelab.ru codelab.ru
Пример
В отличие от традиционных материалов, когда в качестве примера использования наперебой рассматривают реализацию через команды пунктов меню (главного и контекстного) – приведем другой не менее частый случай. В настоящее время довольно повсеместно используется идея модульного, взаимозаменяемого программирования, при котором у нас есть некий единый каркас приложения, а дополнительная функциональность реализуется в виде отдельных, независимых классов-модулей. При этом нет никаких взаимосвязей между каркасом и модулями, все полностью независимо: каркас лишь конфигурируется на этапе загрузки определенным количеством модулей далее по запросу пользователя, он вызывает на выполнение определенный модуль или сразу несколько, взаимодействуя с ними через единый «модульный» интерфейс, в котором обычно достаточно одной какой-либо операции запуска, типа Execute(), Run() и т.д. codelab.ru оригинал codelab.ru источникСоответственно, наша система имеет единый общий каркас и наша задача добавить необходимые нам модули. Модульный интерфейс имеет вид: Module , где GetMenu() – возвращает содержимое меню управления данным модулем. codelab.ru codelab.ru источник оригинал
оригинал codelab.ru источник codelab.ru
Известные применения паттерна Команда (Command)
Быть может, впервые паттерн команда появился в работе Генри Либермана Henry Lieberman. В системе МасАрр команды широко применяются для реализации допускающих отмену операций. В ЕТ++, InterViews и Unidraw также имеются классы, описываемые паттерном команда. Так, в библиотеке Interviews определен абстрактный класс Action, который определяет всю функциональность команд. Есть и шаблон ActionCallback, параметризованный действием Action, который автоматически инстанцирует подклассы команд. codelab.ru codelab.ru источник оригиналисточник оригинал codelab.ru codelab.ru
Родственные паттерны
Паттерн компоновщик можно использовать при реализации макрокоманд. codelab.ru оригинал источник codelab.ruКоманда, которую нужно копировать перед помещением в список истории, ведет себя, как прототип. источник codelab.ru оригинал codelab.ru
Реализации: java(5) +добавить реализацию
1) Module.java, code #487[автор:this]
2) ImageGallery.java, code #488[автор:this]
3) SalesReports.java, code #489[автор:this]
4) MultiPage.java, code #490[автор:this]
5) InfoPage.java, code #491[автор:this]



