Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Delegate: Паттерн проектирования
Delegate — это паттерн проектирования, при котором один объект передает (делегирует) ответственность за выполнение задачи другому объекту. Это альтернатива наследованию: вместо того чтобы расширять функциональность через наследование класса, мы используем композицию и передаем вызовы другому объекту.
Концепция
# Наследование (неправильно для этого случая)
class Bird:
def fly(self):
return "Flying..."
class Penguin(Bird): # Пингвин наследует, но пингвины не летают!
def fly(self):
return "Can't fly"
# Delegate — композиция
class FlyingBehavior:
def fly(self):
pass
class NormalFly(FlyingBehavior):
def fly(self):
return "Flying normally"
class CannotFly(FlyingBehavior):
def fly(self):
return "Cannot fly"
class Bird:
def __init__(self, flying_behavior: FlyingBehavior):
self.flying_behavior = flying_behavior # Делегируем поведение
def fly(self):
return self.flying_behavior.fly() # Передаем вызов делегату
# Использование
eagle = Bird(NormalFly())
print(eagle.fly()) # "Flying normally"
penguin = Bird(CannotFly())
print(penguin.fly()) # "Cannot fly"
Вместо того чтобы Penguin наследовал Bird и переопределял fly(), мы просто подставляем разное поведение через конструктор. Это паттерн Delegate.
Когда и почему использовать
Проблема с наследованием:
# Иерархия быстро становится сложной
Bird
├── FlyingBird
│ ├── Eagle
│ ├── Sparrow
│ └── Swallow
└── NonFlyingBird
├── Penguin
├── Ostrich
└── Kiwi
# А если нам нужны разные стили полета?
# FastFlyer, SlowFlyer, DayFly, NightFly?
# Взрыв комбинаторики!
Решение через Delegate (Strategy pattern):
class Bird:
def __init__(self, flying_behavior, eating_behavior, nesting_behavior):
self.flying = flying_behavior
self.eating = eating_behavior
self.nesting = nesting_behavior
# Теперь любую птицу можно собрать из компонентов
eagle = Bird(
flying_behavior=FastFly(),
eating_behavior=MeatEating(),
nesting_behavior=HighNesting()
)
penguin = Bird(
flying_behavior=NoFly(),
eating_behavior=FishEating(),
nesting_behavior=IceNesting()
)
Практические примеры в Python
Пример 1: Логирование (Delegate паттерн)
class Logger:
"""Интерфейс для логирования"""
def log(self, message: str):
pass
class ConsoleLogger(Logger):
def log(self, message: str):
print(f"[CONSOLE] {message}")
class FileLogger(Logger):
def log(self, message: str):
with open('app.log', 'a') as f:
f.write(f"[FILE] {message}\n")
class Service:
def __init__(self, logger: Logger):
self.logger = logger # Делегируем логирование
def do_work(self):
self.logger.log("Starting work") # Передаем вызов делегату
# ... работа ...
self.logger.log("Work done")
# Использование
service_console = Service(ConsoleLogger())
service_console.do_work()
# Output: [CONSOLE] Starting work
# [CONSOLE] Work done
service_file = Service(FileLogger())
service_file.do_work()
# Пишет в app.log
Пример 2: Обработчик платежей
from abc import ABC, abstractmethod
class PaymentProcessor(ABC):
@abstractmethod
def process(self, amount: float) -> bool:
pass
class StripeProcessor(PaymentProcessor):
def process(self, amount: float) -> bool:
print(f"Processing ${amount} via Stripe")
return True
class PayPalProcessor(PaymentProcessor):
def process(self, amount: float) -> bool:
print(f"Processing ${amount} via PayPal")
return True
class Order:
def __init__(self, processor: PaymentProcessor):
self.processor = processor # Делегируем обработку платежей
def checkout(self, amount: float):
if self.processor.process(amount):
print(f"Order confirmed for ${amount}")
else:
print("Payment failed")
# Использование
stripe_order = Order(StripeProcessor())
stripe_order.checkout(99.99)
# Processing $99.99 via Stripe
# Order confirmed for $99.99
paypal_order = Order(PayPalProcessor())
paypal_order.checkout(49.99)
# Processing $49.99 via PayPal
# Order confirmed for $49.99
Delegate vs Наследование
# НАСЛЕДОВАНИЕ — Отношение IS-A
class Dog(Animal):
pass
# Dog ЭТО Animal
# DELEGATE — Отношение HAS-A (Композиция)
class Dog:
def __init__(self, brain: AnimalBrain):
self.brain = brain
# Dog ИМЕЕТ brain
# Принцип: Предпочитай композицию наследованию!
Сравнение:
# Наследование
class AdvancedList(list):
def custom_method(self):
pass
# Delegate
class CustomList:
def __init__(self):
self._items = [] # Внутри есть список
def custom_method(self):
pass
def append(self, item):
self._items.append(item) # Делегируем список
Delegate в реальных фреймворках
Django views:
# Вместо наследования, можно использовать mixins (которые делегируют)
from django.views.generic import ListView
from django.contrib.auth.mixins import LoginRequiredMixin
class ProfileView(LoginRequiredMixin, ListView):
# LoginRequiredMixin делегирует проверку авторизации
pass
FastAPI dependency injection:
from fastapi import Depends
def get_current_user():
# Это функция-делегат для получения текущего пользователя
return {...}
@app.get("/me")
def get_me(user = Depends(get_current_user)):
# Мы делегируем получение пользователя функции get_current_user
return user
Плюсы и минусы
Плюсы:
Гибкость — легко менять поведение в runtime
Тестируемость — просто подставить mock
Переиспользуемость — компоненты можно комбинировать
Избегаем фрагильного базового класса
Нет проблем с множественным наследованием
Минусы:
Больше кода (boilerplate)
Может быть медленнее наследования (но это микро-оптимизация)
Немного сложнее для понимания поначалу
Резюме
Delegate — это паттерн, при котором объект передает выполнение задачи другому объекту вместо наследования. Это основа Strategy паттерна, Dependency Injection и лучший способ избежать сложных иерархий наследования. В Python делегирование реализуется через конструктор (инъекция зависимости) или явное обращение к объекту-делегату.