Ответ
Паттерн 'Стратегия' — это поведенческий паттерн проектирования, который позволяет определять семейство алгоритмов, инкапсулировать каждый из них и делать их взаимозаменяемыми. Это позволяет клиенту выбирать нужный алгоритм во время выполнения.
Компоненты паттерна:
- Context (Контекст): Класс, который использует одну из стратегий. Он хранит ссылку на объект-стратегию и делегирует ему выполнение алгоритма.
- Strategy (Стратегия): Абстрактный базовый класс или интерфейс, который определяет общий метод для всех конкретных стратегий.
- ConcreteStrategy (Конкретная стратегия): Классы, реализующие интерфейс
Strategy, каждый со своей версией алгоритма.
Пример реализации
Представим, что у нас есть контекст, который должен сортировать данные, но способ сортировки может меняться.
from abc import ABC, abstractmethod
from typing import List, Type
# 1. Интерфейс Стратегии
class SortStrategy(ABC):
@abstractmethod
def sort(self, data: List) -> List:
pass
# 2. Конкретные стратегии
class AscendingSort(SortStrategy):
"""Сортировка по возрастанию."""
def sort(self, data: List) -> List:
return sorted(data)
class DescendingSort(SortStrategy):
"""Сортировка по убыванию."""
def sort(self, data: List) -> List:
return sorted(data, reverse=True)
# 3. Контекст
class Sorter:
def __init__(self, strategy: SortStrategy):
self._strategy = strategy
def set_strategy(self, strategy: SortStrategy):
"""Позволяет сменить стратегию на лету."""
self._strategy = strategy
def execute_sort(self, data: List):
print(f"Используется стратегия: {self._strategy.__class__.__name__}")
result = self._strategy.sort(data)
print(f"Результат: {result}")
return result
# Использование
data_to_sort = [5, 2, 8, 1, 9, 4]
# Изначально используем сортировку по возрастанию
sorter = Sorter(AscendingSort())
sorter.execute_sort(data_to_sort)
# Вывод:
# Используется стратегия: AscendingSort
# Результат: [1, 2, 4, 5, 8, 9]
# Динамически меняем стратегию на сортировку по убыванию
sorter.set_strategy(DescendingSort())
sorter.execute_sort(data_to_sort)
# Вывод:
# Используется стратегия: DescendingSort
# Результат: [9, 8, 5, 4, 2, 1]
Преимущества паттерна:
- Гибкость: Позволяет легко добавлять новые алгоритмы, не изменяя код контекста.
- Изоляция: Код, данные и зависимости алгоритмов изолированы в своих классах.
- Следование принципу открытости/закрытости: Система открыта для расширения (новые стратегии), но закрыта для модификации (не нужно менять класс
Sorter).
Ответ 18+ 🔞
Так, слушай сюда, про этот паттерн "Стратегия". Представь себе, ты — главный по сортировке, царь и бог. Но вот беда: сегодня начальству надо по возрастанию, завтра — по убыванию, а послезавтра какой-нибудь ебаный менеджер придумает сортировку по цвету или размеру ботинка. И что, каждый раз переписывать всю свою, блядь, логику? Да ну нахуй!
Вот тут-то этот паттерн и выручает, как спасительный хуй в шторм. Суть проще пареной репы, хоть и звучит умно.
Что это за зверь? Это такой способ сказать: "Эй, чувак, вот у тебя куча разных алгоритмов (стратегий) сделать одно и то же. Давай не будем мешать всё в одну кучу, а раскидаем по отдельным коробочкам. А наш главный чувак (Контекст) будет просто тыкать пальцем: 'Эту коробочку давай сюда!'".
Из чего состоит этот цирк?
- Стратегия (Strategy): Это как общая инструкция для всех коробочек. Типа, "в каждой коробочке ДОЛЖЕН быть метод
сделать_дело()". Просто бумажка, абстракция, пизда с ушами. - Конкретная Стратегия (ConcreteStrategy): А вот это уже сами коробочки. Одна коробочка — "сортировка по возрастанию". Другая — "по убыванию". Третья, не дай бог, — "по размеру левого яйца". Каждая знает, КАК именно делать дело.
- Контекст (Context): Это наш главный чувак. У него в руках сейчас одна из коробочек. Он сам нихуя не умеет, он просто кричит: "Эй, коробочка, которую я держу, делай дело!". И всё. А если надо сменить поведение — он просто выкидывает старую коробочку и хватает новую. Вообще не парится.
Смотри, как это в коде выглядит, на примере сортировщика:
from abc import ABC, abstractmethod
from typing import List
# 1. Общая инструкция для всех коробочек (Стратегия)
# Говорит: "Любая сортировочная коробочка ДОЛЖНА иметь метод sort()"
class SortStrategy(ABC):
@abstractmethod
def sort(self, data: List) -> List:
pass
# 2. Конкретные коробочки (Конкретные стратегии)
class AscendingSort(SortStrategy):
"""Коробочка 'По возрастанию'."""
def sort(self, data: List) -> List:
# Её внутренняя магия
return sorted(data) # Просто вызываем стандартную сортировку
class DescendingSort(SortStrategy):
"""Коробочка 'По убыванию'."""
def sort(self, data: List) -> List:
# Другая внутренняя магия
return sorted(data, reverse=True)
# 3. Главный чувак (Контекст)
class Sorter:
def __init__(self, strategy: SortStrategy):
# При рождении ему дают первую коробочку в руки
self._strategy = strategy
def set_strategy(self, strategy: SortStrategy):
"""Метод, чтобы сменить коробочку на лету. Охуенно же!"""
self._strategy = strategy
def execute_sort(self, data: List):
# Он не парится КАК сортировать. Он просто тыкает в коробочку.
print(f"Достаю коробочку: {self._strategy.__class__.__name__}")
result = self._strategy.sort(data)
print(f"Насортировал: {result}")
return result
# 4. Использование всей этой хуйни
data = [5, 2, 8, 1, 9, 4]
# Рождается Сортировщик, и ему сразу вручают коробочку AscendingSort
sorter = Sorter(AscendingSort())
sorter.execute_sort(data)
# Вывод:
# Достаю коробочку: AscendingSort
# Насортировал: [1, 2, 4, 5, 8, 9]
# А теперь, ёпта, начальство передумало! Надо по убыванию!
# Без паники! Не переписываем ничего! Просто меняем коробочку.
sorter.set_strategy(DescendingSort())
sorter.execute_sort(data)
# Вывод:
# Достаю коробочку: DescendingSort
# Насортировал: [9, 8, 5, 4, 2, 1]
И в чём, блядь, кайф?
- Гибкость — овердохуища. Захотел новую сортировку (например, по последней цифре)? Берешь новую коробочку (
LastDigitSort), пишешь в ней свой алгоритм и подсовываешь нашемуSorter-у. СамSorterдаже не чихнет, ему похуй. - Всё по полочкам. Каждый алгоритм сидит в своём углу и не лезет к другим. Никаких гигантских
if-elseна 300 строк, где всё перемешано. - Принцип "Открыт/Закрыт" в действии. Систему можно расширять (добавлять новые коробочки-стратегии), но не нужно ковырять и ломать старый, отлаженный код главного чувака (Контекста).
Короче, паттерн "Стратегия" — это когда ты не спрашиваешь "как сделать?", а командуешь: "Сделай!". А уж как — это проблемы той штуки, которую ты держишь в руках. Удобно, чё.