Skip to content

Latest commit

 

History

History
153 lines (117 loc) · 5.6 KB

File metadata and controls

153 lines (117 loc) · 5.6 KB

Паттерн Наблюдатель

Паттерн Наблюдатель (или Издатель - Подписчик) - поведенческий.

Ключевые идеи Observer'а:

  1. Взаимодействие между классами не через управляющие методы, а через события.
  2. Делим классы на две роли Subject (источник) и Observer (подписчик).

Observer может подписаться или отписаться от Subject.

Благодаря данному паттерну:

  1. Принцип разделения ответственности SRP соблюдается.
  2. Publisher не зависит от систем подписчиков (у него просто есть список наследников от общего Observer, и по этому списку он в случае события проходится и вызывает метод).
  3. Распухание кода не грозит, классы могут подписываться и отписываться

Tip

Допустим, у нас будет публикатор постов (Publisher) и различные сервисы (наследуются от Observer), которые его слушают и впоследствии обрабатывают информацию о новом посте.

Publisher использует метод notify, который вызывает у всех подписанных классов метод eventOccurred.

Publisher - наследуется от Subject.

RecomendationEngine, NotificationSender,
AnalyticsCollector, AdvertisingIntegrator - от Observer

Observer'ы подписываются/отписываются от Publisher',
а через методы attach/detach.

Publisher не контролирует, кто именно к нему подписан и
работает со всеми одинаково через интерфейс Observer.

Subject передает Event через метод notify,
а Publisher передает частный случай PostEvent.

from pydantic import BaseModel
from typing import List
from abc import ABC, abstractmethod


class Event:
    def __init__(self, type, details):
        self.type = type
        self.details = details


class Observer(ABC, BaseModel):
    @abstractmethod
    def eventOccurred(self, event: Event):
        pass


class Subject(BaseModel):
    _observers: List[Observer]

    @abstractmethod
    def attach(self, observer: Observer):
        pass

    @abstractmethod
    def detach(self, observer: Observer):
        pass

    @abstractmethod
    def notify(self, event: Event):
        pass


class RecomendationEngine(Observer):
    def eventOccurred(self, event: Event):
        print(
            "Я - Движок рекомендаций, и я получил {} с деталями: {}".format(
                event.type, event.details
            )
        )


class NotificationSender(Observer):
    def eventOccurred(self, event: Event):
        print(
            "Я - Отправитель уведомлений, и я получил {} с деталями: {}".format(
                event.type, event.details
            )
        )


class AnalyticsCollector(Observer):
    def eventOccurred(self, event: Event):
        print(
            "Я - Собиратель аналитики, и я получил {} с деталями: {}".format(
                event.type, event.details
            )
        )


class AdvertisingIntegrator(Observer):
    def eventOccurred(self, event: Event):
        print(
            "Я - Интегратор рекламы, и я получил {} с деталями: {}".format(
                event.type, event.details
            )
        )


class PostEvent(Event):
    def __init__(self, details):
        type = "Post"
        super().__init__(type, details)


class Publisher(Subject):
    _observers: List[Observer] = []

    def attach(self, observer: Observer):
        if observer not in self._observers:
            self._observers.append(observer)

    def detach(self, observer: Observer):
        if observer in self._observers:
            self._observers.remove()

    def notify(self, event: Event):
        for observer in self._observers:
            observer.eventOccurred(event)

    def create_post(self, text):
        event = PostEvent(text)
        print("Создал пост, детали: {}".format(text))
        self.notify(event)


recom_eng = RecomendationEngine()
notif_send = NotificationSender()
analyt_coll = AnalyticsCollector()
advert_integr = AdvertisingIntegrator()

publisher = Publisher()
publisher.attach(recom_eng)
publisher.attach(notif_send)
publisher.attach(analyt_coll)
publisher.attach(advert_integr)

publisher.create_post("Видео с милым котиком")

# output:
# Создал пост, детали: Видео с милым котиком
# Я - Движок рекомендаций, и я получил Post с деталями: Видео с милым котиком
# Я - Отправитель уведомлений, и я получил Post с деталями: Видео с милым котиком
# Я - Собиратель аналитики, и я получил Post с деталями: Видео с милым котиком
# Я - Интегратор рекламы, и я получил Post с деталями: Видео с милым котиком