Поведенческие шаблоны: Strategy, Observer, Command
Моделируйте поведение и взаимодействие с помощью поведенческих шаблонов
«Поведенческие шаблоны: Strategy, Observer, Command» — бесплатный урок PHP Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения PHP Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс PHP Academy содержит 4 уроков всего.
Моделирование поведения
Поведенческие паттерны определяют, как объекты взаимодействуют и распределяют ответственность. Мы сосредоточимся на трёх паттернах, которые постоянно встречаются в реальных системах на PHP:
- Стратегия — заменяет алгоритм во время выполнения.
- Observer — рассылает события заинтересованным слушателям.
- Command — превращает запрос в объект, который можно поставить в очередь, записать в журнал или отменить.
Идея стратегии
Паттерн стратегии определяет семейство взаимозаменяемых алгоритмов за одним интерфейсом и позволяет клиенту выбрать алгоритм во время выполнения. Он заменяет громоздкую конструкцию switch ниже полиморфизмом: контекст делегирует работу той стратегии, которую хранит.
<?php
// The smell Strategy removes: branching on a type code
function price(string $type, float $base): float {
switch ($type) {
case 'standard': return $base + 5;
case 'express': return $base + 15;
default: throw new InvalidArgumentException($type);
}
}
echo price('express', 10), PHP_EOL; // 25
Стратегия в коде
Здесь стоимость доставки зависит от выбранного перевозчика. Каждая стратегия инкапсулирует один алгоритм расчёта цены, а контекст остаётся неизменным при добавлении нового перевозчика.
<?php
interface ShippingStrategy { public function cost(float $weight): float; }
final class Standard implements ShippingStrategy {
public function cost(float $w): float { return 5 + $w * 0.5; }
}
final class Express implements ShippingStrategy {
public function cost(float $w): float { return 15 + $w * 1.2; }
}
final class Cart {
public function __construct(private ShippingStrategy $strategy) {}
public function setStrategy(ShippingStrategy $s): void { $this->strategy = $s; }
public function quote(float $weight): float { return $this->strategy->cost($weight); }
}
$cart = new Cart(new Standard());
echo $cart->quote(10), PHP_EOL; // 10
$cart->setStrategy(new Express());
echo $cart->quote(10), PHP_EOL; // 27
Стратегия с замыканиями
В PHP стратегия не всегда должна быть классом. Для небольших случаев вполне подходит callable или синтаксис вызываемого значения первого класса. Используйте полноценные классы, когда у алгоритма есть собственное состояние или зависимости; для простых вариантов без состояния используйте замыкания.
<?php
$strategies = [
'asc' => fn(array $a) => sort($a) ? $a : $a,
'desc' => fn(array $a) => rsort($a) ? $a : $a,
];
$data = [3, 1, 2];
print_r($strategies['desc']($data)); // [3,2,1]
Идея Observer
Паттерн Observer позволяет наблюдаемому объекту уведомлять множество наблюдателей при изменении состояния, не зная, кто именно ими является. Это отделяет источник события от его обработчиков и лежит в основе систем событий, точек расширения и реактивных обновлений.
Observer в коде
Наблюдаемый объект хранит список наблюдателей и вызывает update() у каждого. Новые слушатели подключаются без изменения логики наблюдаемого объекта.
<?php
interface Observer { public function update(string $event): void; }
final class OrderSubject {
private array $observers = [];
public function subscribe(Observer $o): void { $this->observers[] = $o; }
public function placed(string $id): void {
foreach ($this->observers as $o) { $o->update("order $id placed"); }
}
}
final class EmailObserver implements Observer {
public function update(string $e): void { echo "email: $e" . PHP_EOL; }
}
final class AuditObserver implements Observer {
public function update(string $e): void { echo "audit: $e" . PHP_EOL; }
}
$subject = new OrderSubject();
$subject->subscribe(new EmailObserver());
$subject->subscribe(new AuditObserver());
$subject->placed('42');
Observer и PSR-14
В современном PHP паттерн Observer часто выражается через диспетчеры событий PSR-14: диспетчер направляет объект события зарегистрированным слушателям. Модель остаётся той же: наблюдаемый объект соответствует событию, а наблюдатели — слушателям, но диспетчер ещё сильнее разделяет их и поддерживает события, которые можно остановить. SplObserver и SplSubject существуют в SPL, но сегодня используются редко.
Идея Command
Паттерн Command инкапсулирует запрос в объекте: действие, его получателя и параметры. Поскольку запрос теперь представлен данными, Вы можете поставить его в очередь, записать в журнал, повторить или отменить. Простейшая команда просто представляет намерение как значение, как показано ниже.
<?php
final class SendEmail {
public function __construct(
public readonly string $to,
public readonly string $subject
) {}
}
// The request is now data you can store, serialize, or enqueue
$cmd = new SendEmail('user@example.com', 'Welcome');
echo json_encode($cmd), PHP_EOL;
Command в коде
Каждая команда реализует execute(). Вызывающий объект хранит команды и запускает их, не будучи связанным с тем, что они делают. Добавление undo() превращает это в полноценный стек отмены.
<?php
interface Command { public function execute(): string; }
final class Light { public bool $on = false; }
final class TurnOn implements Command {
public function __construct(private Light $light) {}
public function execute(): string { $this->light->on = true; return 'light on'; }
}
final class TurnOff implements Command {
public function __construct(private Light $light) {}
public function execute(): string { $this->light->on = false; return 'light off'; }
}
final class Invoker {
private array $queue = [];
public function add(Command $c): void { $this->queue[] = $c; }
public function run(): void {
foreach ($this->queue as $c) { echo $c->execute(), PHP_EOL; }
}
}
$light = new Light();
$inv = new Invoker();
$inv->add(new TurnOn($light));
$inv->add(new TurnOff($light));
$inv->run();
Шины Command
Фреймворки строят шину команд на основе этого паттерна: объект передачи данных команды направляется ровно одному обработчику. Промежуточные обработчики вокруг шины могут единообразно добавлять транзакции, проверку и журналирование. Поскольку команды — это обычные сериализуемые объекты, один и тот же обработчик может выполняться синхронно или передаваться рабочему процессу очереди.
Выбор между ними
- Стратегия: одна операция и множество взаимозаменяемых алгоритмов, выбранных вызывающим кодом.
- Observer: одно событие и множество независимых реакций, при этом источник не знает об обработчиках.
- Command: представление запроса в виде объекта, чтобы его можно было поставить в очередь, записать в журнал, повторить или отменить.
Они хорошо сочетаются: обработчик команды может выбрать стратегию и отправить события Observer.
Быстрая проверка
Сопоставьте требование с паттерном.
Итоги
Вы моделировали поведение с помощью трёх паттернов: стратегии для замены алгоритмов во время выполнения, используя классы или замыкания, Observer для рассылки изменений состояния независимым слушателям, лежащего в основе диспетчеров PSR-14, и Command для превращения запросов в объекты, которые можно поставить в очередь, записать в журнал и отменить, лежащего в основе шин команд. Вместе они сохраняют гибкость взаимодействия и ясность ответственности.
Часто задаваемые вопросы
Урок «Поведенческие шаблоны: Strategy, Observer, Command» бесплатный?
Да — полный текст урока «Поведенческие шаблоны: Strategy, Observer, Command» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс PHP Academy, подпишись на CoddyKit PRO. Курс PHP Academy содержит 4 уроков всего.
Чему я научусь в уроке «Поведенческие шаблоны: Strategy, Observer, Command»?
Моделируйте поведение и взаимодействие с помощью поведенческих шаблонов Ты практикуешь PHP Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать PHP Academy?
Предыдущий опыт не требуется. PHP Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Поведенческие шаблоны: Strategy, Observer, Command»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке PHP Academy?
Да. Каждый урок PHP Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Принципы SOLID на практике
- Порождающие шаблоны: Factory, Builder, Singleton
- Структурные шаблоны: Adapter, Decorator, Facade
- Поведенческие шаблоны: Strategy, Observer, Command