Strategy
Один из самых полезных паттернов: заменяем ветвистый if по «режиму» на взаимозаменяемые объекты-алгоритмы.
Strategy определяет семейство взаимозаменяемых алгоритмов, инкапсулирует каждый и позволяет менять их в рантайме независимо от клиента.
Какую задачу решает
Классический запах кода — функция с разрастающимся if режим == "...": способ оплаты, тип сортировки, политика скидки. Каждый новый режим правит общую функцию (нарушая OCP) и усложняет тесты. Strategy выносит каждый вариант в отдельный объект с общим интерфейсом, а клиент держит ссылку на текущую стратегию и просто вызывает её.
Идея и реализация
from abc import ABC, abstractmethod
class Discount(ABC):
@abstractmethod
def apply(self, price): ...
class NoDiscount(Discount):
def apply(self, price):
return price
class PercentDiscount(Discount):
def __init__(self, percent):
self.percent = percent
def apply(self, price):
return price * (1 - self.percent / 100)
class Cart:
def __init__(self, strategy: Discount):
self.strategy = strategy # текущая стратегия
self.total = 0
def checkout(self, price):
return self.strategy.apply(price)
cart = Cart(PercentDiscount(10))
print(cart.checkout(1000))
cart.strategy = NoDiscount() # подмена в рантайме
print(cart.checkout(1000))
Вывод:
900.0 1000
Корзина не знает, как считается скидка — она делегирует это стратегии. Заменить алгоритм можно прямо в рантайме (cart.strategy = ...). Новая политика — это новый класс Discount, код Cart остаётся нетронутым. Это образцовое применение Open/Closed.
Питоничный вариант: просто функция
В Python функции — объекты первого класса, поэтому стратегией часто служит обычная функция, без классов. Это лаконичнее, когда у стратегии нет своего состояния.
def percent(p):
return lambda price: price * (1 - p / 100)
def none():
return lambda price: price
def checkout(price, strategy):
return strategy(price)
print(checkout(1000, percent(20)))
print(checkout(1000, none()))
Вывод:
800.0 1000
Strategy против State
Структурно похожи, но Strategy обычно выбирает клиент ради разных алгоритмов, а в State объект сам меняет своё поведение при смене внутреннего состояния (об этом — в следующем разделе).
Где встречается
Ключ сортировки (sorted(data, key=...) — это стратегия!), политики ретраев, алгоритмы сжатия/шифрования по настройке, способы оплаты, валидаторы форм, ИИ-поведение в играх.
Итог
- Strategy заменяет ветвление по режиму на взаимозаменяемые объекты-алгоритмы.
- Алгоритм можно подменить в рантайме; новый алгоритм не трогает клиента (OCP).
- В Python стратегией часто служит обычная функция.