Strategy - кілька взаємозамінних алгоритмів за спільним інтерфейсом. Код, що їх використовує, не знає, який саме алгоритм працює, і не містить розгалужень за типом.
interface ShippingCalculator
{
public function cost(Order $order): Money;
}
final class NovaPoshtaShipping implements ShippingCalculator { /* ... */ }
final class UkrposhtaShipping implements ShippingCalculator { /* ... */ }
final class PickupShipping implements ShippingCalculator { /* ... */ }
final class Checkout
{
public function __construct(private ShippingCalculator $shipping) {}
public function total(Order $order): Money
{
return $order->subtotal()->add($this->shipping->cost($order));
}
}
Що це дає:
- новий спосіб доставки - новий клас, без зміни
Checkout(принцип відкритості/закритості); - кожну стратегію легко протестувати окремо;
- немає
switch ($order->shipping_method), що розростається з кожним новим варіантом.
У Laravel цей патерн скрізь - під назвою «драйвери»:
- кеш:
file,redis,databaseза контрактомStore; - файлові диски: локальний, S3, FTP за спільним API
Storage; - черги, пошта, логи, сесії, хешування - той самий принцип.
Конкретна стратегія обирається конфігурацією (CACHE_STORE=redis), а код працює з контрактом.
Як обирати стратегію під час виконання: через контейнер (прив'язати інтерфейс до реалізації), фабрику чи мапу [метод => клас]. Якщо варіантів два й вони ніколи не множитимуться, простий if часто чесніший за патерн.