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

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

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

Ответ 18+ 🔞

А, слушай, вот эта штука — Наблюдатель! Ну, паттерн такой, поведенческий. Представь себе, блядь, как в жизни: есть один чувак, который орет на всю улицу, что у него скидка на пиво, а вокруг него куча алкашей, которые эту новость ловят и сразу бегут в магаз. Вот это оно и есть, ёпта!

Кто тут главный по тарелкам:

  • Издатель (Subject): Это тот самый орущий чувак. У него есть какое-то важное состояние — ну, там, цена на пиво упала. И он, сука, обязан проорать об этом всем, кто на него подписался.
  • Подписчик (Observer): Это алкаш, который уши навострил. Его задача — услышать крик и отреагировать: ноги в руки и бежать за дешёвым бухлом.

Соль в чём, блядь: Издатель вообще не в курсе, кто конкретно его слушает — Вася-алкаш, Петя-алкаш или соседская собака, которая тоже бухает. Ему похуй! Главное, чтобы у слушателя была нужная дырка (интерфейс), в которую можно орать. Это и есть слабая связанность, красота!

Смотри, как на Питоне выглядит эта пьянка:

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: ОРУ ВСЕМ, ЧТО ПРОИЗОШЛО '{event_type}'!")
        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_type}' случилось. Данные: '{data}'.")

class EmailListener(IListener):
    def update(self, event_type: str, data: any):
        print(f"EmailSender: Ща спам накидаю всем про событие '{event_type}'!")

# Ну и поехали, блядь!
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, где кнопка (издатель) орет "меня нажали!", а десять обработчиков (подписчики) тут же начинают суетиться.
  • Ну и вообще, для реактивного программирования — модно, блядь.

Чем хорош, сука?

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