Menu
CoddyTech

Паттерн Observer

Часть раздела Объектно-ориентированное программирование путешествия по Python на Coddy. Урок 47 из 64.

Паттерн «Наблюдатель» создаёт отношение «один ко многим», при котором один объект (субъект) уведомляет несколько объектов (наблюдателей), когда его состояние изменяется.

Вот простой класс Subject, который управляет наблюдателями:

class Subject:
    def __init__(self):
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def notify(self, message):
        for observer in self._observers:
            observer.update(message)

Субъект хранит список наблюдателей и может уведомить их всех сразу.

Создайте простые классы наблюдателей:

class EmailNotifier:
    def update(self, message):
        print(f"Email sent: {message}")

class SMSNotifier:
    def update(self, message):
        print(f"SMS sent: {message}")

У каждого наблюдателя есть метод update, который вызывается при получении уведомления.

Используй шаблон «Наблюдатель»:

# Создать субъект
news = Subject()

# Создать наблюдателей
email = EmailNotifier()
sms = SMSNotifier()

# Добавить наблюдателей к субъекту
news.add_observer(email)
news.add_observer(sms)

# Уведомить всех наблюдателей
news.notify("Breaking news: Python is awesome!")

Создайте практический пример с отслеживанием цены акций:

class Stock:
    def __init__(self, symbol, price):
        self.symbol = symbol
        self._price = price
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def set_price(self, price):
        self._price = price
        self.notify()
    
    def notify(self):
        for observer in self._observers:
            observer.update(self.symbol, self._price)

class Investor:
    def __init__(self, name):
        self.name = name
    
    def update(self, symbol, price):
        print(f"{self.name} notified: {symbol} is now ${price}")

# Используйте трекер акций
apple_stock = Stock("AAPL", 150)

investor1 = Investor("Alice")
investor2 = Investor("Bob")

apple_stock.add_observer(investor1)
apple_stock.add_observer(investor2)

apple_stock.set_price(155)  # Уведомляет всех инвесторов

Вывод:

Email sent: Breaking news: Python is awesome!
SMS sent: Breaking news: Python is awesome!
Alice notified: AAPL is now $155
Bob notified: AAPL is now $155

Ключевой момент: шаблон «Наблюдатель» позволяет одному объекту автоматически уведомлять множество других при изменении чего-либо. Субъект поддерживает список наблюдателей и при необходимости вызывает их метод update. Это полезно для уведомлений, систем событий и синхронизации разных частей приложения.

challenge icon

Задание

Средне

Реализуйте шаблон «Наблюдатель», создав систему мониторинга погоды. Вам нужно создать два класса в указанных областях кода.

Шаг 1: Создайте класс WeatherStation

Напишите класс WeatherStation там, где указано в комментарии. Этот класс должен:

  • Наследоваться от класса Subject (используйте class WeatherStation(Subject):)
  • При инициализации:
    • Вызвать конструктор родительского класса с помощью super().__init__()
    • Задать начальную температуру 0 с помощью атрибута с одним подчёркиванием self._temperature (соглашение Python для внутреннего атрибута)
  • Реализовать set_temperature(self, temperature):
    • Обновить внутренний атрибут температуры
    • Вызвать self.notify(self._temperature), чтобы уведомить всех наблюдателей
  • Реализовать get_temperature(self):
    • Вернуть текущее значение температуры

Шаг 2: Создайте класс WeatherDisplay

Напишите класс WeatherDisplay там, где указано в комментарии. Этот класс должен:

  • Наследоваться от класса Observer (используйте class WeatherDisplay(Observer):)
  • При инициализации:
    • Принять параметр name
    • Сохранить имя в self.name
  • Реализовать update(self, temperature):
    • Вывести сообщение об обновлении температуры в точном формате, указанном ниже

Формат сообщения:

Когда дисплей получает обновление температуры, он должен вывести в точности:

Display [name]: Current temperature is [temperature]C

Пример использования:

# Create weather station and displays
station = WeatherStation()
phone_display = WeatherDisplay("Phone")
tablet_display = WeatherDisplay("Tablet")

# Attach displays to station
station.attach(phone_display)
station.attach(tablet_display)

# Update temperature - both displays will be notified
station.set_temperature(25.5)

# Output:
# Display Phone: Current temperature is 25.5C
# Display Tablet: Current temperature is 25.5C

Важные замечания:

  • Методы attach() и detach() уже реализованы в базовом классе Subject — вам не нужно реализовывать их или вызывать в классе WeatherStation
  • В приведённом выше примере использования station.attach(phone_display) вызывается пользователем вашего класса, а не внутри реализации WeatherStation
  • Классу WeatherStation достаточно вызвать self.notify(), когда температура изменится, — базовый класс Subject выполнит остальную работу
  • Сосредоточьтесь на реализации трёх обязательных методов в WeatherStation и двух обязательных методов в WeatherDisplay, как указано выше

Попробуйте сами

class Subject:
    def __init__(self):
        self._observers = []
    
    def attach(self, observer):
        self._observers.append(observer)
        
    def detach(self, observer):
        self._observers.remove(observer)
        
    def notify(self, data):
        for observer in self._observers:
            observer.update(data)
            
class Observer:
    def update(self, data):
        pass

# Напишите здесь свой класс WeatherStation

# Напишите здесь свой класс WeatherDisplay

quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Python