Какие знаешь поведенческие паттерны проектирования?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Поведенческие паттерны проектирования
Поведенческие паттерны (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 — для добавления операций без изменения классов
Правильное применение паттернов делает код более гибким, тестируемым и поддерживаемым.