Шаблон команды кажется излишне сложным (что я не понимаю?)

Я прочитал о шаблоне команд и думаю, что что-то упускаю. Объект Command существует для того, чтобы абстрагироваться от деталей объекта Receiver. Мне кажется, что мы могли бы просто остановиться здесь и хранить ссылки на объекты Command для выполнения соответствующего метода в нужное время.

Зачем же тогда нужен Invoker? Какое преимущество дает эта дополнительная косвенность? Мы уже скрыли детали Приемника за Командой, какова мотивация того, что Команда должна быть скрыта от клиента?


person Chris Tonkinson    schedule 19.05.2011    source источник
comment
У меня есть пример на Java, который может быть полезен для понимания концепций: stackoverflow.com/questions/35276941/   -  person Ravindra babu    schedule 09.02.2016


Ответы (4)


Что ж, если так выразиться, это кажется довольно сложным, но часто Receiver вообще не обязательно должен быть объектом. Это может быть немного больше, чем просто выполняемая функция (как событие). Кроме того, вызывающий объект не обязательно должен быть классом. Это просто то, что запускает команду. Это также может быть обработчик события в кнопке.

Даже Википедия приводит несколько примеров, где этот шаблон используется без фактической реализации полных отдельных классов. для вызывающего и принимающего. Примером может служить диалоговое окно мастера, в котором графический интерфейс заполняет объект команды, а кнопка «Готово» запускает его. Таким образом, этот класс GUI (который у вас есть в любом случае) является одновременно клиентом и инициатором.

person GolezTrol    schedule 19.05.2011
comment
Если один и тот же объект является и клиентом, и вызывающим, это противоречит цели шаблона. Смотрите мой собственный ответ и ответ от @MerlynMorgan-Graham. - person jaco0646; 18.10.2018
comment
@ jaco0646 Частично, конечно, но #Это зависит от остальной части вашего приложения. Расширяя пример мастера, базовый класс мастера может реализовывать основные шаги, включая вызов (против абстрактного интерфейса), в то время как потомок создает команду. Это один шаг от выполнения всего в форме до извлечения этой логики в построитель команд. Поэтому я не согласен с тем, что это полностью противоречит цели шаблона. Но да, в сценарии с нуля вам придется сделать еще один шаг, чтобы в полной мере извлечь выгоду из каждого его аспекта. - person GolezTrol; 18.10.2018
comment
Базовый класс, который реализует основные шаги, откладывая другие шаги на абстрактный интерфейс, реализуемый потомками, является определением шаблона метода шаблона. Конечно, это полезный шаблон, но он сильно отличается от шаблона Command. Описание мастера (в настоящее время) в Википедии достаточно расплывчато, чтобы его можно было реализовать с помощью любого количества шаблонов. (По моему опыту, Википедия вообще плохо разбирается в шаблонах проектирования.) - person jaco0646; 18.10.2018

Если вы передаете команды другого типа, полезно использовать Invoker. Вы можете использовать один и тот же Invoker для выполнения разных конкретных команд. На другом узле пометка Receiver с помощью ConcreteCommand вместо Invoker допускает слабую связь. Receiver может изменить имя метода (например, switchOn на swithcOnTV), как в этом примере:

Сообщение по теме: Использование шаблона проектирования команд

Чтобы понять назначение Invoker, я бы хотел, чтобы вы сослались на эту статью о ресторанах и Варианты использования автосервиса.

Официант (Invoker) принимает заказ из Customer на своей подушке. Затем Order ставится в очередь для повара заказа и попадает к повару (Receiver), где он обрабатывается.

Клиент Customer. Он отправляет запрос Receiver через официанта, которым является Invoker. Официант инкапсулирует команду (в данном случае заказ), записывая ее на чеке, а затем размещает ее, создавая объект ConcreteCommand, который является самой командой.

Receiver будет тем поваром, который после завершения работы над всеми приказами, которые были отправлены ему до рассматриваемой команды, приступает к работе над ним.

Еще одним заметным аспектом примера является тот факт, что панель для заказов не поддерживает только заказы из меню, поэтому она может поддерживать команды для приготовления множества разных блюд.

person Ravindra babu    schedule 10.02.2016

Насколько я могу судить, весь смысл шаблона в том, чтобы иметь своего рода производителя команд и своего рода потребителя команд, но позволять производителю создавать или изменять команды без изменения потребителя.

В шаблоне производитель называется «Клиент», а потребитель — «Вызывающий».

Это объектно-ориентированный обратный вызов.

Зачем же тогда нужен Invoker

Насколько я могу судить из всех примеров в Википедии, вызывающий не имеет определенного форма. Это просто некоторый код, который принимает абстрактную команду.

Мне кажется, что мы могли бы просто остановиться на этом и сохранить ссылки на объекты Command.

Если в вашем коде есть смысл для вещи, которая вызывает команды, принимать или хранить ссылки на абстрактные команды, значит, вы уже реализовали вызывающую программу.

Если один бит кода является и производителем, и потребителем, шаблон команды бесполезен. Это имеет смысл только тогда, когда вы передаете абстрактные команды чему-то, что хочет их вызвать.

person Merlyn Morgan-Graham    schedule 19.05.2011

Мы уже спрятали детали Получателя за Командой,

Совершенно верно, но кто скрывает эти подробности и от кого они спрятаны? Ответ заключается в том, что тот, кто создает экземпляр реализации команды, выполняет скрытие, а тот, кто вызывает абстракцию команды, скрывается от него. Ясно, что нет никакого смысла в том, чтобы оба этих действия выполнялись одним объектом, так же, как вы не можете что-то скрыть от себя.

Таким образом, Client создает экземпляр ConcreteCommand и передает его Invoker, который знает только об интерфейсе Command. По сути, клиент выполняет внедрение зависимостей для Invoker.

Также обратите внимание, что существуют разные способы реализации ConcreteCommand (см. https://stackoverflow.com/a/35617012/1371329). . Если у ConcreteCommand есть какой-то механизм для динамического обнаружения собственного Receiver, то внедрение зависимостей может быть ненужным.

person jaco0646    schedule 18.10.2018