0Pricing
PHP Academy · Урок

Поведенческие шаблоны: 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 — локальная установка не требуется.

Все уроки этого курса

  1. Принципы SOLID на практике
  2. Порождающие шаблоны: Factory, Builder, Singleton
  3. Структурные шаблоны: Adapter, Decorator, Facade
  4. Поведенческие шаблоны: Strategy, Observer, Command
← Назад к PHP Academy