Что это
Паттерн Стратегия делает алгоритм заменяемым: окружающий код остаётся тем же, а взаимозаменяемая часть — как считать цену, как сортировать, как сжимать — подставляется как значение.
В PHP это делается легко: замыкания — полноценные значения, поэтому стратегия часто представляет собой просто Closure в свойстве. Ни интерфейса, ни дополнительного класса — присвойте другое замыкание, и поведение изменится.
Пример: заменяемый расчёт цены
Метод checkout() не меняется никогда; правило расчёта цены — это замыкание в свойстве. Обычная цена, Black Friday, скидка участнику клуба — три замыкания, один магазин.
Стратегия — это замыкание
Три расчёта одной и той же суммы 50 дают три итога — различается только присвоенное замыкание. Точно так же работает и usort: вы передаёте ему стратегию сравнения.
Вывод: PHP-скрипт
<?php
// В PHP стратегия — это всего лишь замыкание.
class Shop {
public function __construct(public \Closure $pricing) {}
public function checkout(float $price): void {
printf("итого: %.2f\n", ($this->pricing)($price));
}
}
$regular = fn(float $p): float => $p;
$blackFriday = fn(float $p): float => $p * 0.7;
$member = fn(float $p): float => $p - 5;
$shop = new Shop($regular);
$shop->checkout(50);
$shop->pricing = $blackFriday;
$shop->checkout(50);
$shop->pricing = $member;
$shop->checkout(50);
Когда применять
Применяйте, когда алгоритм меняется, а его окружение — нет: правила расчёта цены, политики повторных попыток, порядки сортировки, режимы проверки.
Не применяйте, когда алгоритм один и реального второго не предвидится. Используйте интерфейс с классами вместо замыкания только тогда, когда стратегии нужно собственное состояние или несколько методов.
Плюсы и минусы
Плюсы: поведение заменяется во время выполнения; каждая стратегия небольшая и тестируется отдельно; в PHP это почти бесплатно — замыкание и присваивание.
Минусы: выбранная стратегия не видна в месте вызова — отладка означает поиск того, что было присвоено; слишком много микростратегий дробят простую логику.