Как реализовать паттерн проектирования Стратегия в PHP?

«Как реализовать паттерн проектирования Стратегия в PHP?» — вопрос из категории Паттерны, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Паттерн Стратегия инкапсулирует семейство алгоритмов, делая их взаимозаменяемыми. Это позволяет выбирать алгоритм во время выполнения и избегать условных операторов.

Реализация в PHP:

// 1. Интерфейс стратегии
interface PaymentStrategy {
    public function pay(int $amount): void;
}

// 2. Конкретные стратегии
class CreditCardPayment implements PaymentStrategy {
    private string $cardNumber;

    public function __construct(string $cardNumber) {
        $this->cardNumber = $cardNumber;
    }

    public function pay(int $amount): void {
        // Логика оплаты картой
        echo "Списано $amount руб. с карты " . substr($this->cardNumber, -4);
    }
}

class PayPalPayment implements PaymentStrategy {
    private string $email;

    public function __construct(string $email) {
        $this->email = $email;
    }

    public function pay(int $amount): void {
        // Логика PayPal
        echo "Списано $amount руб. с аккаунта {$this->email}";
    }
}

// 3. Контекст
class PaymentContext {
    private PaymentStrategy $strategy;

    public function setStrategy(PaymentStrategy $strategy): void {
        $this->strategy = $strategy;
    }

    public function executePayment(int $amount): void {
        $this->strategy->pay($amount);
    }
}

// Использование
$context = new PaymentContext();

// Выбор стратегии динамически
if ($userPrefersCard) {
    $context->setStrategy(new CreditCardPayment('4111111111111111'));
} else {
    $context->setStrategy(new PayPalPayment('user@example.com'));
}

$context->executePayment(5000);

Ключевые преимущества:

  • Устраняет длинные if/else или switch конструкции
  • Соответствует принципу Open/Closed (можно добавлять новые стратегии без изменения контекста)
  • Упрощает тестирование — каждая стратегия тестируется изолированно
  • В Laravel часто используется вместе с Service Container для внедрения зависимостей