Ответ
Наблюдатель (Observer) — это поведенческий паттерн проектирования, который создает механизм подписки, позволяющий одним объектам следить за изменениями в других объектах и реагировать на них.
Основные участники:
- Издатель (Subject/Observable): Объект, который содержит важное состояние и уведомляет подписчиков о его изменениях.
- Подписчик (Observer/Listener): Объект, который хочет получать уведомления об изменениях в издателе.
Ключевая идея: Издатель не знает ничего о конкретных классах подписчиков, только о том, что они реализуют общий интерфейс. Это обеспечивает слабую связанность между компонентами системы.
Пример на Python:
Создадим простой менеджер событий (EventManager
), который уведомляет подписчиков (LoggerListener
, EmailListener
) о различных событиях.
from abc import ABC, abstractmethod
from typing import List
# Интерфейс подписчика
class IListener(ABC):
@abstractmethod
def update(self, event_type: str, data: any):
pass
# Издатель
class EventManager:
def __init__(self):
self._listeners: List[IListener] = []
def subscribe(self, listener: IListener):
self._listeners.append(listener)
def unsubscribe(self, listener: IListener):
self._listeners.remove(listener)
def notify(self, event_type: str, data: any):
print(f"nEventManager: Notifying about '{event_type}' event...")
for listener in self._listeners:
listener.update(event_type, data)
# Конкретные подписчики
class LoggerListener(IListener):
def update(self, event_type: str, data: any):
print(f"Logger: Event '{event_type}' with data '{data}' was logged.")
class EmailListener(IListener):
def update(self, event_type: str, data: any):
print(f"EmailSender: Sending email about '{event_type}' event.")
# Клиентский код
manager = EventManager()
logger = LoggerListener()
email_sender = EmailListener()
manager.subscribe(logger)
manager.subscribe(email_sender)
manager.notify("user_login", {"user_id": 123})
manager.unsubscribe(email_sender)
manager.notify("order_placed", {"order_id": 456})
Когда использовать:
- Когда изменения в состоянии одного объекта требуют изменения в других, но вы не хотите, чтобы эти объекты были жестко связаны.
- В системах обработки событий (GUI, веб-фреймворки).
- Для реализации реактивного программирования.
Преимущества:
- Слабая связанность: Издатель и подписчики независимы друг от друга.
- Гибкость: Можно добавлять и удалять подписчиков на лету.