TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #395 905
День триста тридцать третий. #DesignPatterns
Паттерны проектирования
5. Паттерн «Наблюдатель» (Observer)
Существует два способа общения между двумя программными элементами. Компонент 1 может обратиться к Компоненту 2 для получения каких-то данных или выполнения некоторой операции, либо Компонент 2 может уведомить Компонент 1 о некотором событии. Первая модель взаимодействия называется pull-моделью, а вторая — push-моделью. В мире ООП push-модель реализуется с помощью паттерна «Наблюдатель».
Назначение: определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом и автоматически обновляются.
Причины использования:
При проектировании некоторого класса у разработчика всегда есть несколько вариантов реализации. Класс А может знать о существовании класса Б и уведомлять его о произошедшем событии. Или же класс А может быть наблюдаемым и уведомлять о некотором событии всех заинтересованных подписчиков. Использование наблюдателей уменьшает связанность между классами/модулями и упрощает повторное использование. Благодаря слабой связанности наблюдаемый объект и наблюдатели могут располагаться на разных уровнях абстракции или слоях приложения. Например, слой пользовательского интерфейса знает о модели, но модель не должна ничего знать о пользовательском интерфейсе.
Классическая диаграмма приведена на рисунке ниже:
- Observer — определяет интерфейс наблюдателя;
- Subject (наблюдаемый объект) — определяет методы подключения и отключения наблюдателей;
- ConcreteObserver — реализует интерфейс наблюдателя;
- ConcreteSubject — конкретный тип наблюдаемого объекта.

На платформе .NET практически невозможно встретить классическую реализацию паттерна «Наблюдатель». Существует несколько вариантов реализации:
1. С помощью делегатов (методов обратного вызова).
Самая простая форма наблюдателя. Для этого достаточно, чтобы класс потребовал делегат в аргументах конструктора и уведомлял вызывающий код с его помощью. Это позволяет гарантировать наличие наблюдателя, а также наблюдаемый объект может не только уведомлять об изменении своего состояния, но и требовать от делегата некоторого результата.
2. С помощью событий (events).
События представляют собой умную оболочку над делегатами, которая позволяет клиентам лишь подписываться на события или отказываться от подписки, а владельцу события — инициировать событие для уведомления всех подписчиков. Разница с первым вариантом в том, что интерфейс наблюдаемого объекта позволяет подписаться на событие любому числу подписчиков. При этом нет гарантии, что эти подписчики вообще будут. Подробнее о событиях
3. С помощью специализированных интерфейсов-наблюдателей.
В некоторых случаях, когда имеется несколько событий или делегатов, их удобно объединить в одном интерфейсе. Данный вариант очень похож на классическую версию паттерна «Наблюдатель», хотя обычно наблюдатель является единственным.
4. С помощью интерфейсов IObserver/IObservable.
Все перечисленные ранее варианты реализации паттерна «Наблюдатель» содержат одно ограничение: они плохо объединяются для получения более высокоуровневого поведения (not composable). Над событиями или делегатами невозможно выполнять операции, которые можно выполнять над последовательностями. С 4-й версии в .NET Framework появилась пара интерфейсов IObserver/IObservable с набором методов расширений, известных под названием реактивных расширений (Rx, Reactive Extensions). Интерфейс IObservable моделирует реактивные последовательности и позволяет работать с наблюдаемыми последовательностями через привычный LINQ-синтаксис. Он предполагает, что однородные события будут периодически повторяться. Наблюдаемый объект может уведомить о новом событии (OnNext), о том, что в процессе события произошла ошибка (OnError), или о том, что цепочка событий завершена (OnComplete). Пример: поток сетевых сообщений от клиента или сервера, координаты устройства и т.п.

Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 5.
More from @netdeveloperdiary
  1. Sep 30, 2026Post #3356
  2. Sep 29, 2026Фото 3 (с) Анатолий Кулаков
  3. Sep 29, 2026День 2799. Конференция DotNext 2026. Часть 1 25 и 26 сентября в Москве прошла очередная ко…
  4. Sep 28, 2026День 2798. #Оффтоп Утиная Типизация в C# с Помощью Перехватчиков. Часть 2 Некоторое время…
  5. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  6. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →