Ответ
Паттерн Наблюдатель (Observer) определяет зависимость типа "один ко многим" между объектами. Когда состояние одного объекта (Субъекта) изменяется, все зависимые от него объекты (Наблюдатели) автоматически уведомляются и обновляются.
Преимущества:
- Слабая связанность (Loose Coupling): Субъект ничего не знает о конкретных классах наблюдателей, только о том, что они реализуют общий интерфейс. Это позволяет изменять и добавлять наблюдателей, не затрагивая код субъекта.
- Гибкость и расширяемость: Новых наблюдателей можно добавлять в любой момент времени, что соответствует принципу открытости/закрытости (Open/Closed Principle).
- Поддержка широковещательных коммуникаций: Одно событие в субъекте может инициировать обновление в неограниченном количестве наблюдателей.
Недостатки:
- Риск утечек памяти: Если наблюдатель не отписался от уведомлений и на него больше нет ссылок, он не будет удален сборщиком мусора, так как субъект все еще хранит на него ссылку.
- Неочевидный порядок обновлений: Паттерн не гарантирует, в каком порядке будут уведомлены наблюдатели, что может привести к непредсказуемому поведению, если их логика зависит друг от друга.
- Проблемы с производительностью: Уведомление большого числа наблюдателей может быть ресурсозатратной операцией и привести к задержкам в работе системы.
Пример на Python:
from abc import ABC, abstractmethod
# Субъект (Издатель)
class WeatherStation:
def __init__(self):
self._observers = []
self._temperature = 0
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self):
for observer in self._observers:
observer.update(self)
def set_temperature(self, temp):
print(f"nПогода изменилась! Новая температура: {temp}°C")
self._temperature = temp
self.notify()
@property
def temperature(self):
return self._temperature
# Интерфейс Наблюдателя
class Observer(ABC):
@abstractmethod
def update(self, subject: WeatherStation):
pass
# Конкретный Наблюдатель
class PhoneDisplay(Observer):
def update(self, subject: WeatherStation):
print(f"[Дисплей телефона]: Температура обновлена: {subject.temperature}°C")
# Использование
station = WeatherStation()
display1 = PhoneDisplay()
station.attach(display1)
station.set_temperature(25)
# Вывод:
# Погода изменилась! Новая температура: 25°C
# [Дисплей телефона]: Температура обновлена: 25°C