Что такое паттерн проектирования «Наблюдатель» (Observer)?

Ответ

Наблюдатель (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, веб-фреймворки).
  • Для реализации реактивного программирования.

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

  • Слабая связанность: Издатель и подписчики независимы друг от друга.
  • Гибкость: Можно добавлять и удалять подписчиков на лету.