Menu
Coddy logo textTech

Паттерн Observer

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

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

Вот простой класс 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)

Subject хранит список observers и может уведомить их всех одновременно.

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

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

Задание

Средне

Реализуйте паттерн Observer, создав систему мониторинга погоды. Вам необходимо создать два класса в обозначенных областях кода.

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

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

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

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

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

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

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

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

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