Паттерн «Наблюдатель»
Часть раздела Объектно-ориентированное программирование путешествия по 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. Это полезно для уведомлений, систем событий и синхронизации нескольких частей приложения.
Задание
СреднеРеализуйте паттерн «Наблюдатель», создав систему мониторинга погоды. Вам нужно создать два класса в предназначенных для этого областях кода.
Шаг 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
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Введение в ООПВнешние файлыКлассы и объектыПараметр selfМетодыАтрибутыМетод-конструктор (__init__)Повторение — простой калькулятор4Наследование
Основы наследованияФункция super()Переопределение методовМножественное наследованиеПорядок разрешения методовПовторение: иерархия сотрудников7Специальные методы
Введение в магические методыПерегрузка операторовМагические методы контейнеровПовторение — пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн «Одиночка»Паттерн «Фабрика»Паттерн «Наблюдатель»Паттерн «Стратегия»2Декораторы
Введение в декораторыДекоратор свойстваДекоратор статического методаДекоратор метода класса5Полиморфизм
Переопределение методов: повторениеУтиная типизацияАбстрактные классы и методыПроектирование интерфейсовПовторение — калькулятор фигур8Продвинутые концепции ООП
Композиция и наследованиеМиксиныСтатические методы и методы классаДекораторы классовМенеджеры контекста11Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»3Свойства классов
Переменные экземпляра и классаДекораторы свойствПриватные атрибутыПовторение — менеджер банковского счёта6Инкапсуляция
Публичные, защищённые и приватные членыМодификаторы доступаСокрытие информацииПродвинутые декораторы свойствПовторение — система учёта студентов12Проект: Система управления библиотекой
Обзор проектаКлассы книг и пользователейСистема выдачи книгФункция поискаИнтерфейс администратораТестирование и интеграцияПотренируйтесь самостоятельно: Онлайн-компилятор Python