← Назад к вопросам

Какие знаешь поведенческие паттерны проектирования?

1.7 Middle🔥 131 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Поведенческие паттерны проектирования

Поведенческие паттерны (Behavioral Patterns) — это паттерны, которые определяют способ взаимодействия между объектами и распределение ответственности. Они помогают создавать гибкие системы с чистым и понятным кодом.

Observer (Наблюдатель)

Паттерн для создания подписки на события. Один объект уведомляет множество других об изменениях:

from typing import List, Callable

class Subject:
    def __init__(self):
        self._observers: List[Callable] = []
    
    def attach(self, observer: Callable) -> None:
        """Подписать наблюдателя на события"""
        if observer not in self._observers:
            self._observers.append(observer)
    
    def detach(self, observer: Callable) -> None:
        """Отписать наблюдателя"""
        self._observers.remove(observer)
    
    def notify(self, message: str) -> None:
        """Уведомить всех наблюдателей"""
        for observer in self._observers:
            observer(message)

class User:
    def update(self, message: str) -> None:
        print(f"User received: {message}")

subject = Subject()
user = User()

subject.attach(user.update)
subject.notify("New post created")  # User received: New post created

Strategy (Стратегия)

Позволяет выбирать алгоритм во время выполнения:

from abc import ABC, abstractmethod

class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount: float) -> str:
        pass

class CreditCardPayment(PaymentStrategy):
    def pay(self, amount: float) -> str:
        return f"Paid {amount} with credit card"

class PayPalPayment(PaymentStrategy):
    def pay(self, amount: float) -> str:
        return f"Paid {amount} with PayPal"

class ShoppingCart:
    def __init__(self, strategy: PaymentStrategy):
        self.strategy = strategy
    
    def checkout(self, amount: float) -> str:
        return self.strategy.pay(amount)

cart = ShoppingCart(CreditCardPayment())
print(cart.checkout(100))  # Paid 100 with credit card

cart2 = ShoppingCart(PayPalPayment())
print(cart2.checkout(50))  # Paid 50 with PayPal

Command (Команда)

Инкапсулирует запрос как объект:

from abc import ABC, abstractmethod
from typing import List

class Command(ABC):
    @abstractmethod
    def execute(self) -> None:
        pass
    
    @abstractmethod
    def undo(self) -> None:
        pass

class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self) -> None:
        self.light.turn_on()
    
    def undo(self) -> None:
        self.light.turn_off()

class Light:
    def turn_on(self) -> None:
        print("Light is ON")
    
    def turn_off(self) -> None:
        print("Light is OFF")

class RemoteControl:
    def __init__(self):
        self.command: Command = None
        self.history: List[Command] = []
    
    def set_command(self, command: Command) -> None:
        self.command = command
    
    def press_button(self) -> None:
        self.command.execute()
        self.history.append(self.command)
    
    def undo_last(self) -> None:
        if self.history:
            self.history.pop().undo()

remote = RemoteControl()
light = Light()
remote.set_command(LightOnCommand(light))
remote.press_button()  # Light is ON
remote.undo_last()  # Light is OFF

State (Состояние)

Позволяет менять поведение объекта в зависимости от состояния:

from abc import ABC, abstractmethod

class State(ABC):
    @abstractmethod
    def handle(self) -> None:
        pass

class PowerOnState(State):
    def handle(self) -> None:
        print("Device is powered ON")

class PowerOffState(State):
    def handle(self) -> None:
        print("Device is powered OFF")

class Device:
    def __init__(self):
        self._state: State = PowerOffState()
    
    def set_state(self, state: State) -> None:
        self._state = state
    
    def request(self) -> None:
        self._state.handle()

device = Device()
device.request()  # Device is powered OFF
device.set_state(PowerOnState())
device.request()  # Device is powered ON

Template Method (Шаблонный метод)

Определяет скелет алгоритма в базовом классе, оставляя детали для подклассов:

from abc import ABC, abstractmethod

class DataProcessor(ABC):
    def process(self) -> None:
        """Шаблонный метод"""
        self.load_data()
        self.validate_data()
        self.transform_data()
        self.save_data()
    
    @abstractmethod
    def load_data(self) -> None:
        pass
    
    @abstractmethod
    def validate_data(self) -> None:
        pass
    
    @abstractmethod
    def transform_data(self) -> None:
        pass
    
    @abstractmethod
    def save_data(self) -> None:
        pass

class CSVProcessor(DataProcessor):
    def load_data(self) -> None:
        print("Loading CSV file")
    
    def validate_data(self) -> None:
        print("Validating CSV data")
    
    def transform_data(self) -> None:
        print("Transforming CSV")
    
    def save_data(self) -> None:
        print("Saving CSV")

processor = CSVProcessor()
processor.process()

Iterator (Итератор)

Последовательно обходит элементы коллекции:

from typing import Iterator, Any

class NumberCollection:
    def __init__(self, numbers: list):
        self.numbers = numbers
    
    def __iter__(self) -> Iterator[int]:
        return iter(self.numbers)
    
    def __next__(self) -> int:
        if self.index >= len(self.numbers):
            raise StopIteration
        value = self.numbers[self.index]
        self.index += 1
        return value

collection = NumberCollection([1, 2, 3, 4, 5])
for num in collection:
    print(num)

Chain of Responsibility (Цепь ответственности)

Передаёт запрос по цепочке обработчиков:

from abc import ABC, abstractmethod
from typing import Optional

class Handler(ABC):
    def __init__(self, next_handler: Optional[Handler] = None):
        self.next_handler = next_handler
    
    @abstractmethod
    def handle(self, request: str) -> str:
        pass

class LogHandler(Handler):
    def handle(self, request: str) -> str:
        print(f"[LOG] Processing: {request}")
        if self.next_handler:
            return self.next_handler.handle(request)
        return "Completed"

class AuthHandler(Handler):
    def handle(self, request: str) -> str:
        print(f"[AUTH] Checking permissions")
        if self.next_handler:
            return self.next_handler.handle(request)
        return "Authorized"

logger = LogHandler(AuthHandler())
logger.handle("user_request")

Visitor (Посетитель)

Добавляет новые операции к объектам без изменения их структуры:

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def accept(self, visitor: Visitor) -> None:
        pass

class Circle(Shape):
    def __init__(self, radius: float):
        self.radius = radius
    
    def accept(self, visitor: Visitor) -> None:
        visitor.visit_circle(self)

class Visitor(ABC):
    @abstractmethod
    def visit_circle(self, circle: Circle) -> None:
        pass

class AreaCalculator(Visitor):
    def visit_circle(self, circle: Circle) -> None:
        area = 3.14 * circle.radius ** 2
        print(f"Circle area: {area}")

circle = Circle(5)
calculator = AreaCalculator()
circle.accept(calculator)  # Circle area: 78.5

Итоговые рекомендации

  • Observer — когда нужна подписка на события
  • Strategy — когда есть несколько способов решить задачу
  • Command — для создания историй операций (undo/redo)
  • State — когда поведение зависит от состояния
  • Template Method — для определения общего алгоритма
  • Iterator — для безопасного обхода коллекций
  • Chain of Responsibility — для обработки запроса несколькими объектами
  • Visitor — для добавления операций без изменения классов

Правильное применение паттернов делает код более гибким, тестируемым и поддерживаемым.

Какие знаешь поведенческие паттерны проектирования? | PrepBro