паттерн observer
Паттерн Observer (наблюдатель) — поведенческий шаблон проектирования, определяющий зависимость «один ко многим» между объектами. Когда состояние одного объекта (субъекта) изменяется, все зависящие от него объекты (наблюдатели) автоматически уведомляются и обновляются. Observer входит в классическую книгу «Банды четырёх» (GoF) и является основой большинства событийных архитектур.
Участники паттерна
Observer строится из двух ключевых ролей. Subject (издатель) — объект, за состоянием которого следят. Он хранит список наблюдателей и уведомляет их при изменениях. Observer (подписчик) — объект, реагирующий на события субъекта. Реализует метод update() или его аналог. Субъект не знает о конкретных реализациях наблюдателей — он работает только с интерфейсом Observer. Это обеспечивает слабую связанность: добавление нового наблюдателя не требует изменения субъекта.
Жизненный цикл
Три этапа: Подписка — наблюдатель регистрируется у субъекта вызовом subscribe() или attach(). Событие — субъект меняет состояние и вызывает notify(), который проходит по списку наблюдателей. Уведомление — каждый наблюдатель получает вызов update() и реагирует по своей логике. Наблюдатель может отписаться через unsubscribe() или detach() — это критически важно для предотвращения утечек памяти.
Push vs Pull уведомления
Push: субъект сам передаёт изменённые данные в метод update(data). Наблюдатель получает всё необходимое сразу, но субъект вынужден знать какие данные нужны наблюдателям. Pull: субъект передаёт только ссылку на себя, а наблюдатель сам запрашивает нужные данные. Наблюдатель получает только то что ему нужно, но требует публичного интерфейса для чтения состояния субъекта.
Практические применения
Observer лежит в основе огромного количества современных систем. GUI-фреймворки: обработчики событий (клик мыши, нажатие клавиши) — классический Observer. Реактивное программирование: RxJS, RxJava, Reactor строятся на концепции наблюдаемых потоков. Шина событий: EventEmitter в Node.js, EventBus в Android. MVC/MVVM: модель уведомляет представление об изменениях через Observer. WebSocket: сервер уведомляет всех подключённых клиентов о новых данных.
Observer в JavaScript
В современном JS паттерн реализован нативно через EventTarget и addEventListener. RxJS обобщает Observer до полноценных реактивных потоков с операторами map, filter, debounce и сотнями других. MobX использует Observer для автоматического отслеживания изменений состояния в React-приложениях: декоратор @observable делает поле субъектом, а компоненты с @observer автоматически перерисовываются при изменениях.
Проблемы и антипаттерны
Утечки памяти: если наблюдатель не отписывается при уничтожении, субъект удерживает ссылку на него. В JavaScript — распространённая причина медленного роста памяти в SPA. Порядок уведомлений: когда несколько наблюдателей зависят от порядка получения событий, возникают тонкие баги. Каскадные обновления: если наблюдатель при получении события модифицирует субъект, это может вызвать бесконечную цепочку уведомлений.
Observer vs Pub/Sub
В Observer субъект напрямую знает о наблюдателях. В Publish/Subscribe между издателем и подписчиком есть посредник — брокер сообщений (Apache Kafka, RabbitMQ). Pub/Sub обеспечивает большую развязку и масштабируемость, Observer — проще в реализации для локальных сценариев.
Частые вопросы
Где используется паттерн Observer в реальных проектах?
Observer используется повсеместно: обработчики DOM-событий в браузере, реактивные библиотеки (RxJS, MobX), шины событий в мобильных приложениях, системы мониторинга метрик, WebSocket-подписки. Любая система с событийной моделью реализует Observer.
В чём разница между Observer и Pub/Sub?
В Observer субъект напрямую хранит список наблюдателей и вызывает их методы. В Pub/Sub между издателем и подписчиком стоит брокер, который полностью разделяет их. Pub/Sub масштабируется лучше, Observer — проще в реализации.
Как избежать утечек памяти при использовании Observer?
Всегда реализуйте логику отписки и вызывайте её при уничтожении объекта-наблюдателя. В JavaScript используйте WeakRef или WeakMap для хранения наблюдателей. В компонентных фреймворках отписывайтесь в хуках уничтожения (ngOnDestroy, componentWillUnmount).
Другие термины в теме «Архитектура ПО»
Не хватает деталей?
Напишите, что уточнить по теме «паттерн observer» — это помогает улучшать материал и подсказывает, какие термины добавить дальше. Email необязателен: укажите, если хотите ответ только для вас (мы не шлём рассылки).