Menu
CoddyTech

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

Часть раздела Объектно-ориентированное программирование путешествия по 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