Шаблон команды
Эта статья включает список литературы , связанную литературу или внешние ссылки , но ее источники остаются неясными, поскольку в ней отсутствуют встроенные цитаты . ( декабрь 2012 г. ) |
В объектно-ориентированном программировании шаблон команды — это шаблон поведенческого проектирования , в котором объект используется для инкапсуляции всей информации, необходимой для выполнения действия или запуска события в более позднее время. Эта информация включает имя метода, объект, которому принадлежит метод, и значения параметров метода.
С шаблоном команды всегда связаны четыре термина: команда , получатель , инициатор и клиент . Объект команды знает о получателе и вызывает метод получателя. Значения параметров метода-приемника сохраняются в команде. Объект-получатель для выполнения этих методов также сохраняется в объекте команды путем агрегирования . Получатель когда затем выполняет работу, execute()
метод в команде вызывается . Объект -вызыватель знает, как выполнить команду, и, при необходимости, ведет учет выполнения команды. Вызывающий ничего не знает о конкретной команде, он знает только о командном интерфейсе . Объект(ы) вызывающего объекта, объекты команд и объекты-получатели хранятся в клиентском объекте, клиент решает, какие объекты-приемники он назначает объектам команд и какие команды он назначает инициатору. Клиент решает, какие команды выполнять в каких точках. Чтобы выполнить команду, он передает объект команды вызывающему объекту.
Использование объектов команд упрощает создание общих компонентов, которым необходимо делегировать, упорядочивать или выполнять вызовы методов в выбранное ими время без необходимости знать класс метода или параметры метода. Использование объекта-вызова позволяет удобно вести учет выполнения команд, а также реализовывать различные режимы для команд, которыми управляет объект-вызов, без необходимости для клиента знать о существовании учета или режимов.
Центральные идеи этого шаблона проектирования во многом отражают семантику функций первого класса и функций высшего порядка в языках функционального программирования . В частности, объект-вызов — это функция высшего порядка, для которой объект команды является аргументом первого класса.
Обзор
[ редактировать ]Команда [1] Шаблон проектирования — один из двадцати трех известных шаблонов проектирования GoF , которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и повторно использовать.
Использование шаблона проектирования команд может решить следующие проблемы: [2]
- Следует избегать привязки инициатора запроса к конкретному запросу. То есть следует избегать жестких запросов.
- Должна быть возможность настроить объект (который вызывает запрос) с помощью запроса.
Реализация (жесткое привязывание) запроса непосредственно к классу является негибкой, поскольку она связывает класс с конкретным запросом во время компиляции, что делает невозможным указание запроса во время выполнения.
Использование шаблона проектирования команд описывает следующее решение:
- Определите отдельные (командные) объекты, инкапсулирующие запрос.
- Класс делегирует запрос командному объекту вместо того, чтобы напрямую реализовывать конкретный запрос.
Это позволяет настроить класс с помощью командного объекта, который используется для выполнения запроса. Класс больше не связан с конкретным запросом и не знает (независим) о том, как выполняется запрос.
См. также класс UML и диаграмму последовательности ниже.
Структура
[ редактировать ]Класс UML и диаграмма последовательности
[ редактировать ]На приведенной выше UML классов диаграмме Invoker
класс не реализует запрос напрямую.Вместо, Invoker
относится к Command
интерфейс для выполнения запроса ( command.execute()
), что делает Invoker
независимо от того, как выполняется запрос. Command1
класс реализует Command
интерфейс, выполняя действие над получателем ( receiver1.action1()
).
Диаграмма UML последовательности показывает взаимодействие во время выполнения: Invoker
вызовы объектов execute()
на Command1
объект. Command1
звонки action1()
на Receiver1
объект,который выполняет запрос.
Диаграмма классов UML
[ редактировать ]Использование
[ редактировать ]- Кнопки графического интерфейса и пункты меню
- В на Swing и Borland Delphi программировании
Action
является командным объектом. Помимо возможности выполнить нужную команду, Действие может иметь связанный значок, сочетание клавиш, текст всплывающей подсказки и т. д. Кнопку панели инструментов или компонент пункта меню можно полностью инициализировать, используя только команду действия . Объект - макросов Запись
- Если все действия пользователя представлены объектами команд, программа может записывать последовательность действий, просто сохраняя список объектов команд по мере их выполнения. Затем он может «воспроизвести» те же действия, снова последовательно выполняя те же объекты команд. Если в программу встроен механизм сценариев, каждый командный объект может реализовать toScript() , и действия пользователя можно будет легко записать в виде сценариев.
- Мобильный код
- Используя такие языки, как Java, где код можно передавать в потоковом режиме из одного места в другое через URLClassloaders и Codebases, команды могут обеспечить доставку нового поведения в удаленные места (команда EJB, Master Worker).
- Многоуровневая отмена
- Если все действия пользователя в программе реализованы как объекты команд, программа может хранить стек последних выполненных команд. Когда пользователь хочет отменить команду, программа просто извлекает самый последний объект команды и выполняет ее. метод отмены() .
- сеть
- Можно отправлять по сети целые объекты команд для выполнения на других машинах, например действия игрока в компьютерных играх.
- Параллельная обработка
- Когда команды записываются как задачи для общего ресурса и выполняются многими потоками параллельно (возможно, на удаленных машинах; этот вариант часто называют шаблоном Master/Worker).
- Индикаторы выполнения
- Предположим, что программа имеет последовательность команд, которые она выполняет по порядку. Если каждый объект команды имеет getEstimatedDuration() , программа может легко оценить общую продолжительность. Он может отображать индикатор выполнения, который значимо отражает, насколько программа близка к выполнению всех задач.
- Пулы потоков
- Типичный класс пула потоков общего назначения может иметь addTask() , который добавляет рабочий элемент во внутреннюю очередь задач, ожидающих выполнения. Он поддерживает пул потоков, которые выполняют команды из очереди. Элементы в очереди являются объектами команд. Обычно эти объекты реализуют общий интерфейс, например java.lang.Runnable , который позволяет пулу потоков выполнять команду, даже если сам класс пула потоков был написан без каких-либо знаний о конкретных задачах, для которых он будет использоваться.
- Транзакционное поведение
- Подобно отмене, ядро базы данных или установщик программного обеспечения могут хранить список операций, которые были или будут выполнены. Если один из них выйдет из строя, все остальные можно отменить или отбросить (обычно это называется откатом ). Например, если необходимо обновить две таблицы базы данных, ссылающиеся друг на друга, а второе обновление завершается неудачей, транзакцию можно откатить, чтобы первая таблица не содержала недопустимую ссылку.
- Волшебники
- Часто мастер представляет несколько страниц конфигурации для одного действия, которое происходит только тогда, когда пользователь нажимает кнопку «Готово» на последней странице. В таких случаях естественным способом отделения кода пользовательского интерфейса от кода приложения является реализация мастера с использованием командного объекта. Объект команды создается при первом запуске мастера. Каждая страница мастера сохраняет изменения графического интерфейса в объекте команды, поэтому объект заполняется по мере продвижения пользователя. «Готово» просто вызывает вызов выполнять() . Таким образом, класс команды будет работать.
Терминология
[ редактировать ]Терминология, используемая для описания реализаций шаблонов команд, непоследовательна и поэтому может сбивать с толку.Это результат двусмысленности , использования синонимов и реализаций, которые могут скрыть исходный шаблон, выходя далеко за его пределы.
- Двусмысленность.
- Термин команда неоднозначен. Например, движение вверх, движение вверх может относиться к одной команде (перемещение вверх), которую следует выполнить дважды, или к двум командам, каждая из которых выполняет одно и то же действие (перемещение вверх). Если первая команда добавляется дважды в стек отмены, оба элемента стека относятся к одному и тому же экземпляру команды. Это может быть уместно, когда команду всегда можно отменить одним и тем же способом (например, движение вниз). И в « Банде четырех» , и в приведенном ниже примере Java используется такая интерпретация термина «команда» . С другой стороны, если последние команды добавляются в стек отмены, стек ссылается на два отдельных объекта. Это может быть уместно, когда каждый объект в стеке должен содержать информацию, позволяющую отменить команду. Например, чтобы отменить команду удаления выделения , объект может содержать копию удаленного текста, чтобы его можно было вставить повторно, если удаления выделения необходимо отменить команду . Обратите внимание, что использование отдельного объекта для каждого вызова команды также является примером Схема цепочки ответственности .
- Термин «выполнить» также неоднозначен. командного объекта Это может относиться к запуску кода, определенного методом выполнения . Однако в Microsoft Windows Presentation Foundation команда считается выполненной, когда был вызван метод выполнения команды , но это не обязательно означает, что код приложения был запущен. Это происходит только после некоторой дальнейшей обработки событий.
- Синонимы и омонимы .
- Клиент, Источник, Invoker : нажатие кнопки, кнопки панели инструментов или пункта меню, сочетание клавиш, нажатое пользователем.
- Объект команды, объект маршрутизированной команды, объект действия : одноэлементный объект (например, существует только один
CopyCommand
объект), который знает о сочетаниях клавиш, изображениях кнопок, тексте команды и т. д., связанных с командой. Объект-источник или вызывающий объект вызывает метод выполнения или PerformAction объекта Command или Action. Объект «Команда/Действие» уведомляет соответствующие объекты источника/вызова, когда доступность команды/действия изменилась. Это позволяет кнопкам и пунктам меню становиться неактивными (выделенными серым цветом), когда команда/действие не может быть выполнено/выполнено. - Получатель, целевой объект : объект, который будет скопирован, вставлен, перемещен и т. д. Объект-получатель владеет методом, который вызывается методом выполнения команды . Получатель обычно также является целевым объектом. Например, если объект-получатель является курсором и метод вызывается
moveUp
, то можно было бы ожидать, что курсор является цельюmoveUp
действие. С другой стороны, если код определяется самим объектом команды, целевой объект будет совершенно другим объектом. - Объект команды, аргументы перенаправленного события, объект события : объект, который передается из источника в объект команды/действия, в целевой объект и в код, который выполняет работу. Каждое нажатие кнопки или сочетание клавиш приводит к созданию нового объекта команды/события. Некоторые реализации добавляют дополнительную информацию к объекту команды/события, поскольку она передается от одного объекта (например,
CopyCommand
) в другой (например, раздел документа). В других реализациях объекты команд/событий помещаются в другие объекты событий (например, блок внутри большего блока) по мере их перемещения по линии, чтобы избежать конфликтов имен. (См. также схему цепочки ответственности .) - Хэндлер,
ExecutedRoutedEventHandler
, метод, функция : фактический код, выполняющий копирование, вставку, перемещение и т. д. В некоторых реализациях код обработчика является частью объекта команды/действия. В других реализациях код является частью объекта-получателя/целевого объекта, а в других реализациях код обработчика хранится отдельно от других объектов. - Диспетчер команд, Диспетчер отмены, Планировщик, Очередь, Диспетчер, Вызов : объект, который помещает объекты команд/событий в стек отмены или стек повторов или удерживает объекты команд/событий до тех пор, пока другие объекты не будут готовы к действию с ними, или который направляет объекты команды/события соответствующему объекту получателя/цели или коду обработчика.
- Реализации, выходящие далеко за рамки исходного шаблона команд.
- Microsoft Windows Presentation Foundation (WPF) представляет маршрутизируемые команды, которые сочетают в себе шаблон команды с обработкой событий. В результате объект команды больше не содержит ни ссылки на целевой объект, ни ссылки на код приложения. командного объекта Вместо этого вызов команды выполнения приводит к так называемому выполненному маршрутизированному событию , которое во время туннелирования или всплытия события может столкнуться с так называемым объектом привязки , который идентифицирует цель и код приложения, который выполняется в этот момент.
Пример
[ редактировать ]Эта реализация C++14 основана на реализации до C++98, описанной в книге.
#include <iostream> #include <memory> class Command { public : // объявляет интерфейс для выполнения операции. виртуальная недействительность выполнения () = 0 ; виртуальный ~ Команда () = по умолчанию ; защищено : Команда () = по умолчанию ; }; template < typename Receiver > class SimpleCommand : public Command { // ConcreteCommand public : typedef void ( Receiver ::* Action )(); // определяет привязку между объектом-приемником и действием. SimpleCommand ( std :: shared_ptr <Receiver> receiver_ SimpleCommand , Action action_ ) : получатель ( receiver_.get ) SimpleCommand ) действие ( action_ ) { } ( ( const delete & ) = ; , // правило трех const SimpleCommand & оператор = ( const SimpleCommand & ) = delete ; // реализует выполнение, вызывая соответствующую операцию(и) на приемнике. virtual void выполнить () { ( приемник ->* действие )(); } Частное : Получатель * получатель ; действие Действие ; }; class MyClass { // Получатель public : // знает, как выполнять операции, связанные с выполнением запроса. Любой класс может служить получателем. void action () { std :: cout << "MyClass::action \n " ; } }; int main () { // Интеллектуальные указатели предотвращают утечки памяти. стандартный :: shared_ptr <MyClass> получатель = std :: make_shared <MyClass> ; ) ( // ... std :: unique_ptr < Command > команда = std :: make_unique < SimpleCommand < MyClass > > ( приемник , & MyClass :: action ); // ... команда -> выполнить (); }
Вывод программы
МойКласс :: действие
См. также
[ редактировать ]- Пакетная очередь
- Закрытие
- Очередь команд
- Функциональный объект
- Планировщик заданий
- Модель-представление-контроллер
- Приоритетная очередь
- Шаблон проектирования программного обеспечения
- GoF – Шаблоны проектирования
История
[ редактировать ]Первое опубликованное упоминание об использовании класса Command для реализации интерактивных систем, по-видимому, было в статье Генри Либермана 1985 года. [4] Первое опубликованное описание (многоуровневого) механизма отмены-повтора с использованием класса Command с методами выполнения и отмены , а также списка истории, по-видимому, является первым (1988 г.) изданием Бертрана Мейера книги «Объектно-ориентированное программное обеспечение». Строительство , [5] раздел 12.2.
Ссылки
[ редактировать ]- ^ Эрих Гамма; Ричард Хелм; Ральф Джонсон; Джон Влиссидес (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Эддисон Уэсли. стр. 233 и далее . ISBN 0-201-63361-2 .
- ^ «Шаблон проектирования «Команда» — проблема, решение и применимость» . w3sDesign.com . Архивировано из оригинала 23 сентября 2020 г. Проверено 12 августа 2017 г.
- ^ «Шаблон проектирования «Команда» — структура и сотрудничество» . w3sDesign.com . Проверено 12 августа 2017 г. [ мертвая ссылка ]
- ^ Либерман, Генри (1985). «Системы меню — это нечто большее, чем просто экран». ACM SIGGRAPH Компьютерная графика . 19 (3): 181–189. дои : 10.1145/325165.325235 .
- ^ Мейер, Бертран (1988). Объектно-ориентированное построение программного обеспечения (1-е изд.). Прентис-Холл.