Паттерн «Команда»
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 75 из 91.
Command Pattern — это поведенческий шаблон проектирования, который превращает запрос в самостоятельный объект, содержащий всю информацию о запросе. Это преобразование позволяет передавать запросы в качестве аргументов методов, откладывать или ставить в очередь выполнение запроса, а также поддерживать операции, которые можно отменить.
Представь себе ресторан.
Когда вы заказываете еду, официант записывает ваш заказ на бланке (command), относит его на кухню, а повар execute его. Официанту не нужно знать, как готовить; он просто доставляет command.
Это отделяет запрашивающую сторону от исполняющей.
Вот базовая реализация:
<?php
interface Command {
public function execute(): string;
}class Light {
public function on(): string { return "Light is ON"; }
public function off(): string { return "Light is OFF"; }
}class LightOnCommand implements Command {
public function __construct(private Light $light) {}
public function execute(): string {
return $this->light->on();
}
}class LightOffCommand implements Command {
public function __construct(private Light $light) {}
public function execute(): string {
return $this->light->off();
}
}
invoker запускает команды, не зная, что они делают:
<?php
class RemoteControl {
public function press(Command $command): string {
return $command->execute();
}
}$light = new Light();
$remote = new RemoteControl();
echo $remote->press(new LightOnCommand($light)) . "\n";
echo $remote->press(new LightOffCommand($light));
Вывод:
Light is ON
Light is OFFШаблон Command особенно эффективен, когда вам нужно ставить операции в очередь, реализовать функцию отмены или вести журнал действий. Каждый command самодостаточен, поэтому легко добавлять новые commands, не изменяя существующий код.
Задание
ЛегкоДавайте создадим систему команд текстового редактора с использованием паттерна Command. Текстовым редакторам часто требуется поддерживать такие операции, как запись текста, удаление текста и отмена действий: каждая операция становится самостоятельным объектом команды, который можно выполнить через единый интерфейс.
Вы организуете код в четырёх файлах:
Command.php: Define интерфейсCommandс единственным методомexecute(): string. Это устанавливает contract, которому должны follow все команды редактора.TextEditor.php, Create классTextEditor, представляющий получатель — объект, который фактически выполняет работу. Ваш редактор должен:- Хранить current текстовый Content (начиная с empty строки)
- Иметь метод
write(string $text): string, который добавляет текст к Content и возвращает"Written: [text]" - Иметь метод
clear(): string, который очищает Content и возвращает"Content cleared" - Иметь метод
getContent(): string, который возвращает current Content
Commands.php: Подключить файлы Command и TextEditor. Create два класса команд, которые Implement интерфейсCommand:WriteCommand: ПринимаетTextEditorи строку текста в своём конструкторе. Его методexecute()вызывает методwrite()редактора и возвращает результат.ClearCommand: ПринимаетTextEditorв своём конструкторе. Его методexecute()вызывает методclear()редактора и возвращает результат.
main.php: Подключить файл Commands. Вы получите два входных значения: тип команды ("write"или"clear") и строку текста (используется только для команд записи).Create экземпляр
TextEditor. Based на типе команды Create appropriate объект команды. Затем Create invoker function или простой механизм, который вызываетexecute()у команды и выводит результат.На новой строке выведите current Content редактора в следующем формате:
Content: [content](если он пуст, просто выведитеContent:, ничего не добавляя после пробела).
Этот challenge демонстрирует, как паттерн Command инкапсулирует каждую операцию в виде объекта. invoker не нужно знать, выполняет ли он команду записи или clear command. Он просто вызывает execute() и позволяет команде обрабатывать детали.
Попробуйте сами
<?php
require_once 'Commands.php';
// Прочитать ввод
$commandType = trim(fgets(STDIN)); // "write" или "clear"
$text = trim(fgets(STDIN)); // текст для команды write
// TODO: Создать экземпляр TextEditor
// TODO: На основе типа команды создать соответствующий объект команды
// - Если "write", создать WriteCommand с редактором и текстом
// - Если "clear", создать ClearCommand с редактором
// TODO: Создать механизм invoker, который вызывает execute() у команды
// и выводит результат
// TODO: Вывести текущее содержимое редактора в формате: "Content: [content]"
// (если пусто, просто вывести "Content: " без ничего после пробела)
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Повторение — простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыПовторение — иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateМодификаторы доступа подробноГеттеры и сеттерыСокрытие информацииПродвижение конструктора (8.0)Повторение — система учёта студентов10Продвинутые концепции ООП
Композиция и наследованиеВнедрение зависимостейАнонимные классыПеречисления (PHP 8.1)Файберы (PHP 8.1)Глубокое погружение в клонирование объектовГенераторы и итераторы13Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Репозиторий»2Пространства имён и автозагрузка
Введение в пространства имёнКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerПовторение — структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс и абстрактный классАннотация типов с интерфейсамиПовторение — калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeПовторение — пользовательская коллекция3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищённые свойстваСвойства только для чтения (PHP 8.1)Повторение — менеджер банковского счёта6Полиморфизм
Повторение переопределения методовПолиморфизм через интерфейсыАннотации типов и объединённые типыПозднее статическое связываниеПовторение — обработчик платежей9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования, часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн StrategyПотренируйтесь самостоятельно: Онлайн-компилятор PHP