Ответ
Команда (Command) — это поведенческий паттерн проектирования, который инкапсулирует запрос на выполнение действия в виде объекта. Это позволяет параметризовать клиентов различными запросами, ставить запросы в очередь, логировать их, а также поддерживать отмену операций.
Суть паттерна: Он превращает операцию в самостоятельный объект, содержащий всю информацию, необходимую для её выполнения. Это отделяет объект, инициирующий операцию (Invoker), от объекта, который знает, как её выполнить (Receiver).
Ключевые компоненты:
ICommand: Интерфейс, объявляющий метод выполнения (например,Execute()). Часто включает методUndo().ConcreteCommand: Конкретная реализация команды. Она связывает действие с Получателем (Receiver), реализуя методыExecute/Undo.Invoker: Инициатор команды. Он знает, когда команду нужно выполнить, но не знает, как она выполняется. Хранит ссылку на объект команды.Receiver: Объект, который знает, как выполнить само действие. Команда делегирует ему основную работу.Client: Создаёт объект конкретной команды и связывает его с получателем и инициатором.
Преимущества:
- Отделение отправителя от получателя: Отправитель (Invoker) не зависит от конкретных классов получателей.
- Реализация отмены/повтора (Undo/Redo): Легко реализуется, если команды сохраняют состояние, необходимое для отката.
- Очереди и планирование операций: Команды как объекты можно собирать в очередь, выполнять по расписанию или передавать по сети.
- Сбор сложных команд: Можно создавать макрокоманды (составные команды) из набора простых.
Пример на C# (Управление умным домом с поддержкой отмены):
// 1. Интерфейс команды
public interface ICommand
{
void Execute();
void Undo();
}
// 2. Получатель (Receiver) — знает, как выполнять действия
public class Light
{
private bool _isOn = false;
private string _location;
public Light(string location) => _location = location;
public void TurnOn()
{
_isOn = true;
Console.WriteLine($"Свет в {_location} ВКЛЮЧЕН.");
}
public void TurnOff()
{
_isOn = false;
Console.WriteLine($"Свет в {_location} ВЫКЛЮЧЕН.");
}
}
// 3. Конкретные команды
public class LightOnCommand : ICommand
{
private Light _light;
public LightOnCommand(Light light)
{
_light = light;
}
public void Execute()
{
_light.TurnOn();
}
public void Undo()
{
_light.TurnOff(); // Отмена действия «включить» — это «выключить»
}
}
public class LightOffCommand : ICommand
{
private Light _light;
public LightOffCommand(Light light)
{
_light = light;
}
public void Execute()
{
_light.TurnOff();
}
public void Undo()
{
_light.TurnOn(); // Отмена действия «выключить» — это «включить»
}
}
// 4. Инициатор (Invoker) — пульт с одной кнопкой и поддержкой отмены
public class SimpleRemoteControl
{
private ICommand _slot;
private ICommand _lastCommand; // Для реализации отмены
public void SetCommand(ICommand command)
{
_slot = command;
}
public void ButtonWasPressed()
{
_slot?.Execute();
_lastCommand = _slot; // Запоминаем последнюю выполненную команду
}
public void UndoButtonWasPressed()
{
_lastCommand?.Undo();
_lastCommand = null;
}
}
// 5. Клиентский код
class Program
{
static void Main()
{
// Создаём получателя
Light livingRoomLight = new Light("Гостиной");
// Создаём команды, связывая их с получателем
ICommand lightOn = new LightOnCommand(livingRoomLight);
ICommand lightOff = new LightOffCommand(livingRoomLight);
// Создаём инициатор (пульт)
SimpleRemoteControl remote = new SimpleRemoteControl();
// Настраиваем пульт на команду «Включить свет»
remote.SetCommand(lightOn);
remote.ButtonWasPressed(); // Вывод: Свет в Гостиной ВКЛЮЧЕН.
// Настраиваем пульт на команду «Выключить свет»
remote.SetCommand(lightOff);
remote.ButtonWasPressed(); // Вывод: Свет в Гостиной ВЫКЛЮЧЕН.
// Демонстрация отмены: снова включим свет и отменим действие
remote.SetCommand(lightOn);
remote.ButtonWasPressed(); // Вывод: Свет в Гостиной ВКЛЮЧЕН.
remote.UndoButtonWasPressed(); // Вывод: Свет в Гостиной ВЫКЛЮЧЕН. (отмена)
}
}