Ответ
Паттерн Strategy (Стратегия) — это поведенческий шаблон, который определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Он позволяет изменять алгоритм независимо от клиента, который его использует.
Основная цель: Замена условных операторов (if/switch) на полиморфизм объектов.
Пример на PHP (система оплаты):
// Интерфейс стратегии
interface PaymentStrategy {
public function pay(float $amount): string;
}
// Конкретные стратегии
class CreditCardPayment implements PaymentStrategy {
private string $cardNumber;
private string $cvv;
public function __construct(string $cardNumber, string $cvv) {
$this->cardNumber = $cardNumber;
$this->cvv = $cvv;
}
public function pay(float $amount): string {
// Логика взаимодействия с платежным шлюзом для карт
return "Paid $amount using Credit Card ending with " . substr($this->cardNumber, -4);
}
}
class PayPalPayment implements PaymentStrategy {
private string $email;
public function __construct(string $email) {
$this->email = $email;
}
public function pay(float $amount): string {
// Логика API PayPal
return "Paid $amount using PayPal account: $this->email";
}
}
class CryptoPayment implements PaymentStrategy {
private string $walletAddress;
public function __construct(string $walletAddress) {
$this->walletAddress = $walletAddress;
}
public function pay(float $amount): string {
// Логика работы с блокчейном
return "Paid $amount in crypto to wallet: " . substr($this->walletAddress, 0, 8) . "...";
}
}
// Контекст, использующий стратегию
class ShoppingCart {
private PaymentStrategy $paymentStrategy;
public function setPaymentStrategy(PaymentStrategy $strategy): void {
$this->paymentStrategy = $strategy;
}
public function checkout(float $totalAmount): string {
if (!isset($this->paymentStrategy)) {
throw new RuntimeException('Payment strategy not set.');
}
return $this->paymentStrategy->pay($totalAmount);
}
}
// Использование
$cart = new ShoppingCart();
$cart->setPaymentStrategy(new CreditCardPayment('4111111111111111', '123'));
echo $cart->checkout(149.99) . "n";
// Paid 149.99 using Credit Card ending with 1111
$cart->setPaymentStrategy(new PayPalPayment('user@example.com'));
echo $cart->checkout(89.50) . "n";
// Paid 89.5 using PayPal account: user@example.com
Преимущества:
- Изоляция кода алгоритма: Каждая стратегия — отдельный класс, который легко тестировать.
- Избегание условных операторов: Контекст не содержит логики выбора алгоритма.
- Взаимозаменяемость: Стратегии можно менять на лету.
- Соответствует принципу открытости/закрытости: Новые алгоритмы добавляются без изменения контекста.
Ответ 18+ 🔞
Слушай, а вот паттерн Strategy — это вообще огонь, если ты задолбался этими бесконечными if и switch на триста веток. Представь, у тебя есть какая-то логика, которая может выполняться по-разному. Вместо того чтобы городить говнокод с условиями, ты просто выносишь каждый вариант в отдельный класс-стратегию. Получается семейство алгоритмов, и ты можешь их подменять, как перчатки, — ёпта, красота же!
Суть в чём: Ты определяешь общий интерфейс для всех алгоритмов, а потом каждый конкретный алгоритм (стратегию) реализуешь в своём классе. Контекст (тот, кто использует алгоритм) работает с этим интерфейсом и ему да похуй, какая именно стратегия ему подсунута. Главное, чтобы у неё был нужный метод. В итоге вместо монструозной процедуры с ветвлениями получаешь чистый полиморфизм — охуенно, правда?
Смотри на примере системы оплаты, тут всё понятно станет:
// Вот наш главный договор — интерфейс стратегии. Все, кто хочет быть стратегией, должны уметь платить.
interface PaymentStrategy {
public function pay(float $amount): string;
}
// Конкретные стратегии — это просто разные способы заплатить.
// Картой, например.
class CreditCardPayment implements PaymentStrategy {
private string $cardNumber;
private string $cvv;
public function __construct(string $cardNumber, string $cvv) {
$this->cardNumber = $cardNumber;
$this->cvv = $cvv;
}
public function pay(float $amount): string {
// Тут была бы логика общения с платёжным шлюзом, но нам неважно.
return "Paid $amount using Credit Card ending with " . substr($this->cardNumber, -4);
}
}
// А это оплата через PayPal. Совсем другой алгоритм, но тот же интерфейс.
class PayPalPayment implements PaymentStrategy {
private string $email;
public function __construct(string $email) {
$this->email = $email;
}
public function pay(float $amount): string {
// Логика API PayPal, но нам опять **да похуй** на детали.
return "Paid $amount using PayPal account: $this->email";
}
}
// Ну и крипта, куда же без неё. Тоже стратегия.
class CryptoPayment implements PaymentStrategy {
private string $walletAddress;
public function __construct(string $walletAddress) {
$this->walletAddress = $walletAddress;
}
public function pay(float $amount): string {
// Блокчейн, майнинг, **ёб твою мать** — но интерфейс тот же!
return "Paid $amount in crypto to wallet: " . substr($this->walletAddress, 0, 8) . "...";
}
}
// А вот контекст — корзина покупок. Ей главное, чтобы ей дали стратегию оплаты.
class ShoppingCart {
private PaymentStrategy $paymentStrategy;
// Подсовываем ей любую стратегию на лету. Вжух — и оплата картой, вжух — и PayPal.
public function setPaymentStrategy(PaymentStrategy $strategy): void {
$this->paymentStrategy = $strategy;
}
public function checkout(float $totalAmount): string {
if (!isset($this->paymentStrategy)) {
throw new RuntimeException('Payment strategy not set.');
}
// Корзина вызывает pay(), а как именно он работает — её не ебёт.
return $this->paymentStrategy->pay($totalAmount);
}
}
// Использование — просто **ебушки-воробушки**!
$cart = new ShoppingCart();
// Сказали платить картой — платит картой.
$cart->setPaymentStrategy(new CreditCardPayment('4111111111111111', '123'));
echo $cart->checkout(149.99) . "n";
// Выведет: Paid 149.99 using Credit Card ending with 1111
// Передумали — переключились на PayPal. Ничего не ломается.
$cart->setPaymentStrategy(new PayPalPayment('user@example.com'));
echo $cart->checkout(89.50) . "n";
// Выведет: Paid 89.5 using PayPal account: user@example.com
В чём, блядь, профит?
- Код алгоритмов изолирован. Каждая стратегия — отдельный класс. Хочешь протестировать оплату криптой? Тестируй только её, не трогая всю корзину. Волнение ебать от такой простоты.
- Нет этих ебучих условных операторов. Не нужно в
checkout()писатьif ($method == 'card') {...} elseif ($method == 'paypal') {...}. Контекст чистый, как слеза младенца. - Взаимозаменяемость на ходу. Стратегию можно поменять прямо перед вызовом, как в примере выше.
- Соответствует принципу открытости/закрытости. Надо добавить оплату через СБП? Создаёшь новый класс
SbpPayment, реализуешь интерфейс — и всё, блядь. Контекст (ShoppingCart) менять не нужно. Это же ни хуя себе удобно!
Короче, если видишь, что у тебя одна и та же операция делается по-разному в зависимости от какого-то условия — это крик о помощи и намёк, что пора заюзать Strategy.
Видео-ответы
▶
▶
▶
▶