Что такое паттерн "Команда" (Command)

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

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

Преимущества паттерна «Команда»

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

Пример:

  • Команды: Включить свет, выключить свет.
  • Получатель: Свет (лампа).
  • Отправитель: Пульт управления.

Где применяется паттерн «Команда»?

  • Системы с отменой/повтором действий.
  • Обработка очередей запросов.
  • Реализация транзакций.
  • GUI — обработка событий от кнопок, меню.

Пример реализации на JavaScript

// Получатель class Light { on() { console.log("Свет включен"); } off() { console.log("Свет выключен"); } } // Команда включения света class LightOnCommand { constructor(light) { this.light = light; } execute() { this.light.on(); } undo() { this.light.off(); } } // Команда выключения света class LightOffCommand { constructor(light) { this.light = light; } execute() { this.light.off(); } undo() { this.light.on(); } } // Отправитель class RemoteControl { setCommand(command) { this.command = command; } pressButton() { this.command.execute(); } pressUndo() { if (this.command.undo) { this.command.undo(); } } } // Использование const light = new Light(); const lightOn = new LightOnCommand(light); const lightOff = new LightOffCommand(light); const remote = new RemoteControl(); remote.setCommand(lightOn); remote.pressButton(); // Свет включен remote.pressUndo(); // Свет выключен remote.setCommand(lightOff); remote.pressButton(); // Свет выключен remote.pressUndo(); // Свет включен

Когда стоит использовать паттерн «Команда»?

  • Нужно инкапсулировать операции и отделить отправителя от получателя.
  • Требуется реализовать отмену и повтор действий.
  • Необходимо ставить операции в очередь или логировать их.
  • Хотите строить сложные действия из простых команд.

Отличие от других паттернов

  • В отличие от цепочки обязанностей, команда инкапсулирует запрос, а не передаёт его дальше.
  • В отличие от состояния, команда фокусируется на выполнении операций.

Плюсы паттерна

  • Упрощает добавление новых операций.
  • Позволяет реализовать отмену и повтор.
  • Повышает гибкость архитектуры.
  • Позволяет реализовать макрокоманды (составные команды).

Минусы паттерна

  • Увеличивает количество классов.
  • Может усложнить структуру проекта при простых задачах.