Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy — урок 75 из 91.

Паттерн Команда (Command Pattern) — это поведенческий паттерн проектирования, который превращает запрос в самостоятельный объект, содержащий всю информацию о запросе. Такая трансформация позволяет передавать запросы в качестве аргументов методов, откладывать или ставить выполнение запроса в очередь, а также поддерживать операции отмены.

Представьте себе ресторан.

Когда вы заказываете еду, официант записывает ваш заказ на листке (команду), относит его на кухню, и повар его выполняет. Официанту не нужно знать, как готовить; он просто передает команду.

Это отделяет отправителя запроса от исполнителя.

Вот базовая реализация:

<?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 Pattern) отлично подходит в тех случаях, когда вам нужно ставить операции в очередь, реализовывать функциональность отмены или логировать действия. Каждая команда самодостаточна, что позволяет легко добавлять новые команды, не изменяя существующий код.

challenge icon

Задание

Легко

Давайте создадим командную систему текстового редактора, используя паттерн Команда (Command Pattern). Текстовым редакторам часто требуется поддерживать такие операции, как написание текста, удаление текста и отмена действий — каждая операция становится автономным объектом команды, который может быть выполнен через единый интерфейс.

Вы организуете свой код в четырех файлах:

  • Command.php — Определите интерфейс Command с единственным методом execute(): string. Это устанавливает контракт, которому должны следовать все команды редактора.
  • TextEditor.php — Создайте класс TextEditor, который представляет собой получателя (receiver) — объект, который фактически выполняет работу. Ваш редактор должен:
    • Хранить текущее текстовое содержимое (начните с пустой строки)
    • Иметь метод write(string $text): string, который добавляет текст к содержимому и возвращает "Written: [text]"
    • Иметь метод clear(): string, который очищает содержимое и возвращает "Content cleared"
    • Иметь метод getContent(): string, который возвращает текущее содержимое
  • Commands.php — Подключите файлы Command и TextEditor. Создайте два класса команд, реализующих интерфейс Command:
    • WriteCommand — Принимает TextEditor и текстовую строку в своем конструкторе. Его метод execute() вызывает метод редактора write() и возвращает результат.
    • ClearCommand — Принимает TextEditor в своем конструкторе. Его метод execute() вызывает метод редактора clear() и возвращает результат.
  • main.php — Подключите файл Commands. Вы получите два входных значения: тип команды ("write" или "clear") и текстовую строку (используется только для команд записи).

    Создайте экземпляр TextEditor. В зависимости от типа команды создайте соответствующий объект команды. Затем создайте функцию-инициатор (invoker) или простой механизм, который вызывает execute() для команды и выводит результат.

    На новой строке выведите текущее содержимое редактора в следующем формате: Content: [content] (если оно пустое, просто выведите Content: без ничего после пробела).

Эта задача демонстрирует, как паттерн Команда инкапсулирует каждую операцию в виде объекта. Инициатору не нужно знать, выполняет ли он команду записи или очистки — он просто вызывает execute() и позволяет команде обработать детали.

Шпаргалка

Паттерн Команда (Command Pattern) — это поведенческий паттерн проектирования, который инкапсулирует запрос в виде отдельного объекта, содержащего всю информацию о запросе. Это позволяет передавать запросы в качестве аргументов методов, ставить операции в очередь и поддерживать отмену действий.

Паттерн отделяет отправителя (invoker) от исполнителя (receiver), подобно тому как официант передает заказы повару, не зная, как именно готовится блюдо.

Базовая структура

Определите интерфейс Command с методом execute():

interface Command {
    public function execute(): string;
}

Создайте класс-получатель (receiver), который выполняет фактическую работу:

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)

Инициатор запускает команды, не зная деталей их реализации:

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));

Преимущества

Паттерн Команда идеально подходит для постановки операций в очередь, реализации функционала отмены или логирования действий. Каждая команда самодостаточна, что позволяет легко добавлять новые команды без изменения существующего кода.

Попробуйте сами

<?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Проверьте себя

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

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