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

Что такое паттерн Медиатор?

2.0 Middle🔥 191 комментариев
#DevOps и инфраструктура#Django

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

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

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

Что такое паттерн Медиатор?

Медиатор (Mediator) — это поведенческий паттерн проектирования, который централизует сложную коммуникацию между множеством объектов. Вместо того чтобы объекты общались друг с другом напрямую, они взаимодействуют только через медиатора.

Основная идея

Представьте аэропорт. Вместо того чтобы самолёты напрямую связывались друг с другом и диспетчерской вышкой, все коммуникации идут только через диспетчера (медиатора). Это предотвращает хаос и упрощает управление.

Проблема, которую решает Медиатор

Без паттерна — множество прямых связей (spaghetti code):

class Dialog:
    def __init__(self):
        self.button = Button()
        self.checkbox = Checkbox()
        self.textbox = Textbox()
        
        # Каждый компонент должен знать о других
        self.button.on_click = lambda: self._handle_button_click()
        self.checkbox.on_change = lambda: self._handle_checkbox_change()
        self.textbox.on_change = lambda: self._handle_textbox_change()
    
    def _handle_button_click(self):
        if self.checkbox.is_checked:
            self.textbox.enable()
        else:
            self.textbox.disable()
    
    def _handle_checkbox_change(self):
        if self.checkbox.is_checked:
            self.button.enable()
        else:
            self.button.disable()
    
    def _handle_textbox_change(self):
        # Более сложная логика взаимодействия
        pass

С паттерном — централизованная коммуникация через медиатора.

Реализация паттерна Медиатор

from abc import ABC, abstractmethod

# Абстрактный Медиатор
class Mediator(ABC):
    @abstractmethod
    def notify(self, sender, event):
        pass

# Компоненты (Collegue'и)
class Component:
    def __init__(self, mediator: Mediator):
        self._mediator = mediator
    
    def emit_event(self, event):
        """Отправить событие медиатору"""
        self._mediator.notify(self, event)

class Button(Component):
    def click(self):
        self.emit_event('button_clicked')

class Checkbox(Component):
    def __init__(self, mediator: Mediator):
        super().__init__(mediator)
        self.is_checked = False
    
    def toggle(self):
        self.is_checked = not self.is_checked
        self.emit_event('checkbox_toggled')

class Textbox(Component):
    def __init__(self, mediator: Mediator):
        super().__init__(mediator)
        self.enabled = True
    
    def set_enabled(self, enabled):
        self.enabled = enabled
        print(f"Textbox {'enabled' if enabled else 'disabled'}")

# Конкретный Медиатор
class DialogMediator(Mediator):
    def __init__(self):
        self.button = Button(self)
        self.checkbox = Checkbox(self)
        self.textbox = Textbox(self)
    
    def notify(self, sender, event):
        """Обработать событие от компонента"""
        if sender == self.button and event == 'button_clicked':
            self._on_button_click()
        
        elif sender == self.checkbox and event == 'checkbox_toggled':
            self._on_checkbox_toggle()
    
    def _on_button_click(self):
        if self.checkbox.is_checked:
            self.textbox.set_enabled(True)
        else:
            print("Нельзя включить textbox, если checkbox не отмечен")
    
    def _on_checkbox_toggle(self):
        if self.checkbox.is_checked:
            self.button.enable()
        else:
            self.button.disable()

# Использование
mediator = DialogMediator()

mediator.checkbox.toggle()  # checkbox теперь true
mediator.button.click()     # Включит textbox
mediator.checkbox.toggle()  # checkbox теперь false
mediator.button.click()     # Не включит textbox

Реальный пример: система управления рейсами

from typing import List
from enum import Enum

class FlightStatus(Enum):
    WAITING = "waiting"
    BOARDING = "boarding"
    TAXIING = "taxiing"
    FLYING = "flying"
    LANDED = "landed"

class AirportMediator:
    """Диспетчер аэропорта (Медиатор)"""
    
    def __init__(self):
        self.flights: List['Flight'] = []
        self.gates: List['Gate'] = []
    
    def register_flight(self, flight: 'Flight'):
        self.flights.append(flight)
        flight.mediator = self
    
    def request_gate(self, flight: 'Flight') -> bool:
        """Выделить ворота для самолёта"""
        available_gate = next(
            (gate for gate in self.gates if not gate.is_occupied),
            None
        )
        
        if available_gate:
            available_gate.assign_flight(flight)
            print(f"Ворота {available_gate.number} назначены рейсу {flight.number}")
            return True
        
        print(f"Свободных ворот нет для рейса {flight.number}")
        return False
    
    def notify_flight_status(self, flight: 'Flight', status: FlightStatus):
        """Обработать изменение статуса рейса"""
        print(f"Рейс {flight.number}: {status.value}")
        
        if status == FlightStatus.BOARDING:
            self.request_gate(flight)
        
        elif status == FlightStatus.LANDED:
            # Освободить ворота
            for gate in self.gates:
                if gate.flight == flight:
                    gate.release()
                    print(f"Ворота {gate.number} освобождены")

class Flight:
    def __init__(self, number: str, mediator: AirportMediator):
        self.number = number
        self.mediator = mediator
        self._status = FlightStatus.WAITING
    
    @property
    def status(self):
        return self._status
    
    @status.setter
    def status(self, new_status: FlightStatus):
        self._status = new_status
        self.mediator.notify_flight_status(self, new_status)

class Gate:
    def __init__(self, number: int):
        self.number = number
        self.flight: Flight = None
        self.is_occupied = False
    
    def assign_flight(self, flight: Flight):
        self.flight = flight
        self.is_occupied = True
    
    def release(self):
        self.flight = None
        self.is_occupied = False

# Использование
mediator = AirportMediator()
mediator.gates = [Gate(1), Gate(2), Gate(3)]

flight1 = Flight("AA100", mediator)
flight2 = Flight("BA200", mediator)

flight1.status = FlightStatus.BOARDING  # Запросит ворота
flight2.status = FlightStatus.BOARDING  # Запросит другие ворота
flight1.status = FlightStatus.LANDED    # Освободит ворота

Реальный пример: чат-комната

from datetime import datetime

class ChatRoom:
    """Медиатор — чат-комната"""
    
    def __init__(self, name: str):
        self.name = name
        self.users: List['User'] = []
    
    def add_user(self, user: 'User'):
        self.users.append(user)
        self.broadcast(f"{user.name} присоединился", system=True)
    
    def remove_user(self, user: 'User'):
        self.users.remove(user)
        self.broadcast(f"{user.name} покинул комнату", system=True)
    
    def send_message(self, sender: 'User', message: str):
        timestamp = datetime.now().strftime("%H:%M")
        print(f"[{timestamp}] {sender.name}: {message}")
    
    def broadcast(self, message: str, system=False):
        prefix = "[СИСТЕМА]" if system else ""
        print(f"{prefix} {message}")

class User:
    def __init__(self, name: str, chat_room: ChatRoom):
        self.name = name
        self.chat_room = chat_room
    
    def join(self):
        self.chat_room.add_user(self)
    
    def leave(self):
        self.chat_room.remove_user(self)
    
    def send(self, message: str):
        self.chat_room.send_message(self, message)

# Использование
room = ChatRoom("General")
alice = User("Alice", room)
bob = User("Bob", room)

alice.join()
bob.join()
alice.send("Привет, Боб!")
bob.send("Привет, Алиса!")
alice.leave()

Медиатор vs Observer

Observer: объекты уведомляют подписчиков об изменениях Медиатор: объекты отправляют события медиатору, а он решает, что делать

# Observer — push уведомления
button.on_click.subscribe(lambda: textbox.enable())

# Медиатор — события через центр
button.click()  # -> Медиатор.notify() -> принимает решение

Преимущества и недостатки

Преимущества:

  • Упрощает коммуникацию между объектами
  • Централизует логику взаимодействия
  • Легче тестировать компоненты отдельно
  • Снижает coupling между объектами

Недостатки:

  • Медиатор может стать God Object (слишком большой)
  • Сложнее отследить в debugger'е
  • Сам медиатор становится критически важным

Когда использовать

  • Диалоги и формы с множественным взаимодействием
  • Системы управления (аэропорты, больницы)
  • Чат-приложения
  • Game event systems
  • Orchestra conductor pattern (дирижёр оркестра)

Заключение

Медиатор — это паттерн для:

  • Упрощения сложных коммуникаций
  • Централизации логики взаимодействия
  • Снижения связанности между объектами
  • Контроля порядка и типа взаимодействия

Используй его, когда у тебя много объектов, которые нужно координировать.