Паттерн Команда (Command) в PHP
Короткий скринкаст: паттерн «Команда» (Command) — превращаем запрос в объект. Пульт хранит команду и вызывает её, не зная, что именно произойдёт: включится или выключится свет.
Описание
Команда превращает запрос в отдельный объект с методом execute. Клиент создаёт команду и передаёт её инициатору — пульту. Пульт хранит команду и по нажатию кнопки просто вызывает execute, не зная ни о лампе, ни о том, что именно произойдёт. Сама команда держит ссылку на получателя — лампу — и решает, какой её метод вызвать. Так запрос становится самостоятельным объектом: его можно хранить, передавать и подменять.
UML-диаграмма
Код
Command.php
interface Command
{
public function execute(): string;
}
Light.php
class Light
{
public function on(): string
{
return 'Light is on';
}
public function off(): string
{
return 'Light is off';
}
}
LightOnCommand.php
class LightOnCommand implements Command
{
public function __construct(private Light $light) {}
public function execute(): string
{
return $this->light->on();
}
}
LightOffCommand.php
class LightOffCommand implements Command
{
public function __construct(private Light $light) {}
public function execute(): string
{
return $this->light->off();
}
}
RemoteControl.php
class RemoteControl
{
private ?Command $command = null;
public function setCommand(Command $command): void
{
$this->command = $command;
}
public function pressButton(): ?string
{
return $this->command?->execute();
}
}
demo.php
require_once 'Command.php';
require_once 'Light.php';
require_once 'LightOnCommand.php';
require_once 'LightOffCommand.php';
require_once 'RemoteControl.php';
$light = new Light;
$remote = new RemoteControl;
$remote->setCommand(new LightOnCommand($light));
echo $remote->pressButton().PHP_EOL;
$remote->setCommand(new LightOffCommand($light));
echo $remote->pressButton().PHP_EOL;
Пример результата
После php demo.php пульт по очереди выполнил две команды, а лампа включилась и выключилась:
Light is on
Light is off
Преимущества
- Превращает запрос в объект: команду можно хранить, передавать и логировать.
- Инициатор не знает ни получателя, ни самой операции.
- Новые команды добавляются без правок пульта и клиента.
- Позволяет легко реализовать очередь, отмену и повтор операций.
Когда использовать
- Когда нужно параметризовать объект действием.
- Когда запросы следует ставить в очередь, логировать или отменять.
- Когда инициатор и получатель не должны знать друг о друге.
- Когда одна и та же операция вызывается из разных мест.
Использование в Laravel
В Laravel Команда — это задания в очереди: класс из app/Jobs/* реализует handle(), а dispatch() кладёт его в очередь, откуда воркер вызывает выполнение, не зная деталей. Тот же принцип у класса Artisan-команд (Illuminate\Console\Command) с методом handle() и у диспетчера Illuminate\Bus\Dispatcher, который направляет команду к её обработчику.