Ответ
Паттерн «Стратегия» (Strategy) — это поведенческий паттерн проектирования, который позволяет определять семейство алгоритмов, инкапсулировать каждый из них в отдельный класс и делать их взаимозаменяемыми. Это позволяет алгоритму изменяться независимо от клиентов, которые его используют.
Преимущества:
- Устранение условных операторов: Заменяет множественные условные конструкции (
if/else
,switch
) полиморфизмом, делая код более чистым, легко читаемым и расширяемым. - Гибкость и расширяемость: Позволяет легко добавлять новые стратегии (алгоритмы) без изменения существующего клиентского кода или других стратегий, следуя принципу открытости/закрытости (Open/Closed Principle).
- Изоляция логики алгоритмов: Каждый алгоритм инкапсулируется в свой собственный класс, что соответствует принципу единственной ответственности (SRP) и улучшает модульность и читаемость кода.
- Упрощение тестирования: Каждую стратегию можно тестировать независимо от контекста, что упрощает процесс отладки и верификации корректности реализации.
Недостатки:
- Увеличение количества классов: Для каждого алгоритма требуется отдельный класс, что может привести к разрастанию кодовой базы, особенно при большом количестве простых стратегий, и усложнить навигацию по проекту.
- Клиент должен знать о стратегиях: Клиентский код должен быть осведомлен о существовании различных стратегий и уметь выбрать подходящую, что может усложнить его логику и увеличить связанность.
- Избыточность для простых алгоритмов: Для очень простых алгоритмов, которые редко меняются, использование паттерна Стратегия может быть избыточным и приводить к ненужному усложнению архитектуры без существенных преимуществ.
Пример реализации паттерна Стратегия для различных способов оплаты:
from abc import ABC, abstractmethod
# Интерфейс стратегии
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount: float):
pass
# Конкретные стратегии
class CreditCardPayment(PaymentStrategy):
def pay(self, amount: float):
print(f"Оплата {amount:.2f} USD через кредитную карту.")
class PayPalPayment(PaymentStrategy):
def pay(self, amount: float):
print(f"Оплата {amount:.2f} USD через PayPal.")
class BitcoinPayment(PaymentStrategy):
def pay(self, amount: float):
print(f"Оплата {amount:.2f} USD через Bitcoin кошелек.")
# Контекст, использующий стратегию
class PaymentContext:
def __init__(self, strategy: PaymentStrategy):
self._strategy = strategy
def set_strategy(self, strategy: PaymentStrategy):
self._strategy = strategy
def execute_payment(self, amount: float):
print("Выполнение платежа...")
self._strategy.pay(amount)
# Использование паттерна
context = PaymentContext(CreditCardPayment())
context.execute_payment(100.50)
context.set_strategy(PayPalPayment())
context.execute_payment(25.00)
context.set_strategy(BitcoinPayment())
context.execute_payment(500.75)
Паттерн Стратегия особенно полезен, когда у вас есть несколько вариантов поведения для одного и того же действия, и вы хотите легко переключаться между ними или добавлять новые без изменения основного кода.