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

Принцип реализации паттерна «наблюдатель» в python сводиться к использованию списка объектов наблюдения, а в случае возникновении события, проходу циклом по этому списку и вызову нужного метода у каждого объекта в списке.

Пример

Предположим у вас есть большой загородный дом окруженный забором, на этом заборе установлены камеры фото\видео наблюдения, вы хотите что бы если кто-то постучался в дверь забора, все камеры камеры тут-же сделали фото.

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

Реализуем класс централизованной систему(пульт управления камерами) и класс самой камеры наблюдения:

from abc import ABC, abstractmethod


class CameraSystem:
    """Централизованная система наблюдения."""
    
    def __init__(self):
        self.__observers = set()

    # Подключить наблюдателя(камеру) к системе. (просто добавляем объект в список).
    def attach(self, observer):
        self.__observers.add(observer)

    # Отключить наблюдателя(камеру) от системы. (просто удаляем объект из список).
    def detach(self, observer):
        self.__observers.remove(observer)

    # Отправка уведомления\команды всем наблюдателям(камерам) подключенным к системе.
    # (Проходимся по списку объектов и вызываем нужный метод).
    def notify(self):
        for observer in self.__observers:
            observer.make_photo()

# Абстрактный класс наблюдателя. 
# Косвенно указывает какие методы необходимо реализовать в его наследниках. 
# Ведь в дальнейшем мы можем подключить к центральной системе не только камеры, но и например автоматические пулеметы ))
class AbstractObserver(ABC):
    @abstractmethod
    def make_photo(self):  # Абстрактный наблюдатель задает метод make_photo
        pass


class Camera(AbstractObserver):
    """Камера наблюдения."""
    
    def __init__(self, name):
        self.name = name

    def make_photo(self):
        print('{} сделала фото'.format(self.name))

Создадим необходимые экземпляры классов и поиграемся с ними.

# Камер на заборе у нас будет 3.
cam1 = Camera('Камера #1')
cam2 = Camera('Камера #2')
cam3 = Camera('Камера #3')

# Создадим центральный пульт управления.
cam_system = CameraSystem()

# Подключим все 3 камеры к пульту управления.
cam_system.attach(cam1)
cam_system.attach(cam2)
cam_system.attach(cam3)

# Оп ! Внимание, пульт каким-то образом понял, что кто то постучал в дверь.
# сообщим всем подключенным к пульту камерам, что нужно сделать фото.
cam_system.notify()

# >>> Камера #1 сделала фото
# >>> Камера #2 сделала фото
# >>> Камера #3 сделала фото

# Отключим первую камеру от пульта, т.к. фотки с нее получаются не четкие :)
cam_system.detach(cam1)

# Вновь происходит событие.
cam_system.notify()

# >>> Камера #2 сделала фото
# >>> Камера #3 сделала фото