Menu
Coddy logo textTech

Паттерн «Команда»

Часть раздела Объектно-ориентированное программирование путешествия по 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, не изменяя существующий код.

challenge icon

Задание

Легко

Давайте создадим систему команд текстового редактора с использованием паттерна 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: " без ничего после пробела)

?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор PHP