Skip to content

Latest commit

 

History

History
116 lines (74 loc) · 12.4 KB

Command.md

File metadata and controls

116 lines (74 loc) · 12.4 KB

Команда

UML

Превращает запросы в объекты, позволяя передавать их как аргументы при вызове методов, ставить запросы в очередь, логировать их, а также поддерживать отмену операций.

Соблюдение Dependency-Inversion UML UML

Применимость

  • Когда вы хотите параметризовать объекты выполняемым действием.

    • Команда превращает операции в объекты. А объекты можно передавать, хранить и взаимозаменять внутри других объектов.

      Скажем, вы разрабатываете библиотеку графического меню и хотите, чтобы пользователи могли использовать меню в разных приложениях, не меняя каждый раз код ваших классы. Применив паттерн, пользователям не придётся изменять классы меню, вместо этого они будут конфигурировать объекты меню различными командами.

  • Когда вы хотите ставить операции в очередь, выполнять их по расписанию или передавать по сети.

    • Как и любые другие объекты, команды можно сериализовать, то есть превратить в строку, чтобы потом сохранить в файл или базу данных. Затем, в любой удобный момент, её можно достать обратно, снова превратить в объект команды, и выполнить. Таким же образом команды можно передавать по сети, логировать или выполнять на удалённом сервере.
  • Когда вам нужна операция отмены.

    • Главная вещь, которая вам нужна, чтобы иметь возможность отмены операций - это хранение истории. Среди многих способов как это делается, паттерн Команда является, пожалуй, самым популярным.

      История команд выглядит как стек, в который попадают все выполненные объекты команд. Каждая команда перед выполнением операции сохраняет текущее состояния объекта, с которым она будет работать. После выполнения операции, копия команды попадает в стек истории, все ещё неся в себе сохранённое состояние объекта. Если потребуется отмена, программа возьмёт последнюю команду из истории и возобновит сохранённое в ней состояние.

      Этот способ имеет две особенности. Во-первых, точное состояние объектов не так-то просто сохранить, ведь часть его может быть приватным. Но с этим может помочь справиться паттерн Снимок.

      Во-вторых, копии состояния могут занимать довольно много оперативной памяти. Поэтому иногда можно прибегнуть к альтернативной реализации, когда вместо восстановления старого состояния, команда выполняет обратное действие. Недостаток этого способа в сложности (а иногда и невозможности) реализации обратного действия.

Шаги реализации

  1. Создайте общий интерфейс команд и определите в нём метод запуска (execute()).

  2. Создайте классы конкретных команд. В каждом классе должно быть поле для хранения ссылки на один или несколько объектов-получателей, которым команда будет перенаправлять основную работу (Делегирование).

    Кроме этого, команда должна иметь поля для хранения параметров, которые нужны при вызове методов получателя. Значения всех этих полей команда должна получать через конструктор.

    И наконец, реализуйте основной метод команды, вызывая в нём те или иные методы получателя.

  3. Добавьте в классы отправителей поля для хранения команд. Объект-отправитель должен принимать готовый объект команды извне через конструктор, либо через сеттер команды.

  4. Измените основной код отправителей так, чтобы они делегировали выполнение действия команде.

  5. Порядок инициализации объектов должен выглядеть так:

  • Создаём объекты получателей. (Создаем лампочку)
  • Создаём объекты команд, связав их с получателями. (Создаем команду вклСвет, передаем в нее лампочку)
  • Создаём объекты отправителей, связав их с командами. (Создаем пульт, передаем в него команду)

Преимущества и недостатки

+ -
Убирает прямую зависимость между объектами, вызывающими операции и объектами, которые их непосредственно выполняют. Усложняет код программы за счёт дополнительных классов.
Позволяет реализовать простую отмену и повтор операций.
Позволяет реализовать отложенный запуск команд.
Позволяет собирать сложные команды из простых.
Соблюдает принцип открытости/закрытости.

Отношения с другими паттернами

  • Цепочка обязанностей, Команда, Посредник и Наблюдатель показывают различные способы работы отправителей запросов с их получателями:

    • Цепочка обязанностей передаёт запрос последовательно через цепочку потенциальных получателей, ожидая, что какой-то из них обработает запрос.

    • Команда устанавливает косвенную одностороннюю связь от отправителей к получателям.

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

    • Наблюдатель передаёт запрос одновременно всем заинтересованным получателям, но позволяет им динамически подписывать или отписываться от таких оповещений.

  • Обработчики в Цепочке обязанностей могут быть выполнены в виде Команд. В этом случае множество разных операций может быть выполнено над одним и тем же контекстом, коим является запрос.

    Но есть и другой подход, в котором сам запрос является Командой, посланной по цепочке объектов. В этом случае одна и та же операция может быть выполнена над множеством разных контекстов, представленных в виде цепочки.

  • Команду и Снимок можно использовать сообща для реализации отмены операций. В этом случе объекты команд будут отображать выполненные действие над объектом, снимки - хранить копию состояния этого объекта до того, как команда была выполнена.

    Команда и Стратегия похожи по духу, но отличаются масштабом и применением:

    • Команду используют, чтобы превратить любые разнородные действия в объекты. Параметры операции превращаются в поля объекта. Этот объект теперь можно логировать, хранить в истории для отмены, передавать во внешние сервисы и так далее.

    • С другой стороны, Стратегия описывает разные способы сделать одно и то же действие, позволяя взаимозаменять эти способы в каком-то объекте контекста. Если Команду нужно копировать перед вставкой в историю выполненных команд, вам может помочь Прототип.

  • Посетитель это более мощный аналог Команды, которую можно выполнить сразу над объектами нескольких классов.