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

Что такое Delegate?

2.7 Senior🔥 201 комментариев
#DevOps и инфраструктура#Django

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

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

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

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 делегирование реализуется через конструктор (инъекция зависимости) или явное обращение к объекту-делегату.