Ответ
Паттерн Command (Команда) — это поведенческий паттерн проектирования, который инкапсулирует запрос в виде объекта. Это позволяет параметризовать клиентов с различными запросами, ставить запросы в очередь, логировать их, а также поддерживать отмену операций.
Зачем он нужен? Чтобы отделить объект, инициирующий операцию (Invoker), от объекта, который знает, как её выполнить (Receiver). Это обеспечивает слабую связность и добавляет возможности управления запросами.
Ключевые компоненты:
Command: Интерфейс с методомexecute()(и частоundo()).ConcreteCommand: Конкретная реализация команды. Связывает действие (Receiver) с параметрами.Invoker: Инициирует выполнение команды (например, кнопка в UI).Receiver: Объект, который знает, как выполнить саму операцию.Client: Создаёт и настраивает конкретную команду.
Пример на Java (с поддержкой отмены):
// 1. Интерфейс команды
interface Command {
void execute();
void undo();
}
// 2. Receiver (Получатель) - знает, как выполнить действие
class Light {
public void turnOn() { System.out.println("Свет включён"); }
public void turnOff() { System.out.println("Свет выключен"); }
}
// 3. ConcreteCommand (Конкретная команда)
class TurnOnLightCommand implements Command {
private Light light;
public TurnOnLightCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
@Override
public void undo() {
light.turnOff();
}
}
// 4. Invoker (Инициатор) - хранит и выполняет команду
class RemoteControl {
private Command command;
private Command lastCommand; // Для отмены
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
if (command != null) {
lastCommand = command;
command.execute();
}
}
public void pressUndo() {
if (lastCommand != null) {
lastCommand.undo();
lastCommand = null;
}
}
}
// 5. Client (Клиент) - настраивает команды
public class Main {
public static void main(String[] args) {
Light livingRoomLight = new Light(); // Receiver
Command turnOn = new TurnOnLightCommand(livingRoomLight); // ConcreteCommand
RemoteControl remote = new RemoteControl(); // Invoker
remote.setCommand(turnOn);
remote.pressButton(); // Вывод: Свет включён
remote.pressUndo(); // Вывод: Свет выключен
}
}
Преимущества:
- Отделение отправителя и получателя: Уменьшает связность.
- Реализация отмены/повтора операций (Undo/Redo).
- Возможность создания составных команд (макросов).
- Постановка команд в очередь или их логирование.
Недостатки:
- Усложняет код из-за введения множества дополнительных классов.
Ответ 18+ 🔞
Так, слушай, смотри, есть у нас в программировании такая хуйня, которая называется Паттерн "Команда". Это, блядь, не приказ какой-то, а такой поведенческий трюк, когда ты заворачиваешь какой-то запрос или действие в отдельный объект, как в конверт. Получается такая инкапсуляция, ёпта!
А нахуя это надо, спросишь? А затем, чтобы тот, кто команду даёт (ну, типа кнопка на пульте), нихрена не знал про того, кто её выполняет (лампочка там, телевизор). Они друг про друга не в курсе, связь слабая — красота! Зато можно команды в очередь ставить, логировать, а главное — отменять, если накосячил. Овердохуище возможностей открывается.
Из каких деталей эта хуйня собирается?
Command(Команда): Просто интерфейс, который говорит: «У любой команды должен быть методexecute()(выполнить) и, желательно,undo()(отменить)». Всё, больше от неё нихуя не требуется.ConcreteCommand(Конкретная команда): А вот это уже реальная пацанская команда. Она знает, кого дергать (Receiver) и что ему сказать. Связующее звено, блядь.Invoker(Инициатор): Это и есть наш пульт, кнопка, менюшка. Его задача — крикнуть команде «Выполняйся!». Сам он нихуя не делает.Receiver(Получатель): А это тот самый работяга, который знает, как конкретно свет включить или музыку прибавить. Объект с реальной логикой.Client(Клиент): Это мы с тобой, которые всё это хозяйство собирают: создают лампочку, команду для неё, и суют эту команду в пульт.
Смотри, как это в коде выглядит, на примере света с отменой:
// 1. Интерфейс команды - контракт для всех
interface Command {
void execute(); // Сделай!
void undo(); // Отмени! (Не всегда, но тут есть)
}
// 2. Receiver (Получатель) - тот, кто реально работает
class Light {
public void turnOn() { System.out.println("Свет включён"); }
public void turnOff() { System.out.println("Свет выключен"); }
}
// 3. ConcreteCommand (Конкретная команда) - "Включи свет"
class TurnOnLightCommand implements Command {
private Light light; // Она знает, какую именно лампу дергать
public TurnOnLightCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn(); // Дёрнула получателя
}
@Override
public void undo() {
light.turnOff(); // И отменить умеет!
}
}
// 4. Invoker (Инициатор) - наш пульт
class RemoteControl {
private Command command;
private Command lastCommand; // Запомним последнюю, чтобы отменить
public void setCommand(Command command) {
this.command = command; // Вставили в пульт нужную команду
}
public void pressButton() {
if (command != null) {
lastCommand = command; // Запомнили
command.execute(); // Выполнили
}
}
public void pressUndo() {
if (lastCommand != null) {
lastCommand.undo(); // Откатили
lastCommand = null;
}
}
}
// 5. Client (Клиент) - собираем конструктор
public class Main {
public static void main(String[] args) {
Light livingRoomLight = new Light(); // Создали лампу (Receiver)
Command turnOn = new TurnOnLightCommand(livingRoomLight); // Создали команду для неё
RemoteControl remote = new RemoteControl(); // Взяли пульт (Invoker)
remote.setCommand(turnOn); // Засунули команду в пульт
remote.pressButton(); // Жмём! -> "Свет включён"
remote.pressUndo(); // Ой, передумал! -> "Свет выключен"
}
}
Что хорошего?
- Развязал всем руки: Отправитель команды и исполнитель теперь не знают друг о друге. Слабая связность — залог гибкости, блядь.
- Отмена/Повтор (Undo/Redo) реализуется почти на раз-два.
- Можно сложные команды делать из простых (макросы).
- Команды можно в очередь складывать или логировать — вообще красота.
Что плохого?
- Классов становится, как говна за баней. На каждую мелкую операцию — свой класс команды. Может перегрузить проект, если им не злоупотреблять.