Паттерн Стратегия (Strategy) в PHP
Короткий скринкаст: паттерн «Стратегия» (Strategy) — алгоритмы можно подменять во время выполнения, не трогая клиента. Пример с разными способами оплаты.
Описание
Стратегия позволяет определить семейство алгоритмов, инкапсулировать каждый из них и сделать их взаимозаменяемыми. Клиент выбирает нужный алгоритм во время выполнения, передавая его в контекст. Интерфейс PaymentStrategy описывает общий метод оплаты. Конкретные стратегии CreditCardPayment и PaypalPayment реализуют разные способы оплаты. Контекст ShoppingCart принимает стратегию через конструктор и делегирует оплату выбранной стратегии в checkout() — сам он не знает, каким именно способом происходит оплата.
UML-диаграмма
Код
PaymentStrategy.php
interface PaymentStrategy
{
public function pay(int $amount): void;
}
CreditCardPayment.php
class CreditCardPayment implements PaymentStrategy
{
public function __construct(private readonly string $cardNumber) {}
public function pay(int $amount): void
{
echo "Paid {$amount} via Credit Card ({$this->cardNumber})\n";
}
}
PaypalPayment.php
class PaypalPayment implements PaymentStrategy
{
public function __construct(private readonly string $email) {}
public function pay(int $amount): void
{
echo "Paid {$amount} via PayPal ({$this->email})\n";
}
}
ShoppingCart.php
class ShoppingCart
{
public function __construct(private readonly PaymentStrategy $strategy) {}
public function checkout(int $amount): void
{
$this->strategy->pay($amount);
}
}
demo.php
require_once 'PaymentStrategy.php';
require_once 'CreditCardPayment.php';
require_once 'PaypalPayment.php';
require_once 'ShoppingCart.php';
$cart = new ShoppingCart(new CreditCardPayment('1234-5678-9012-3456'));
$cart->checkout(100);
$cart = new ShoppingCart(new PaypalPayment('user@example.com'));
$cart->checkout(200);
Пример результата
Paid 100 via Credit Card (1234-5678-9012-3456)
Paid 200 via PayPal (user@example.com)
Преимущества
- Алгоритмы инкапсулированы и легко взаимозаменяемы.
- Клиент отделён от деталей реализации алгоритмов.
- Можно добавлять новые стратегии, не меняя существующий код.
- Следует принципу открытости/закрытости и инверсии зависимостей.
Когда использовать
- Когда нужно выбирать один из нескольких алгоритмов динамически.
- Когда множество классов различаются только поведением.
- Когда нужно скрыть детали алгоритма от клиента.
- Когда поведение может меняться без изменения контекста.
Использование в Laravel
В Laravel Стратегия встречается при выборе различных драйверов: например, разные драйверы очередей (redis, database, sqs), разные способы авторизации, или различные стратегии оплаты в пакетах. Также Illuminate\Support\Facades\Cache позволяет выбирать драйвер кеша во время работы приложения. Контекст использует выбранную стратегию, не зная деталей её реализации.