Давайте рассмотрим паттерн проектирования Адаптер C#, для чего он нужен и какие проблемы он решает. Где можно применять шаблон Adapter C# , а где это будет излишним.
Идея паттерна Наблюдатель
Паттерн (шаблон) проектирования — это продуманный способ построения исходного кода программы для решения часто возникающих в повседневном программировании проблем проектирования. Иными словами, это уже придуманное решения, для типичной задачи. При этом паттерн не готовое решение, а просто алгоритм действий, который должен привести к желаемому результату. Давайте рассмотрим один из наиболее часто используемых поведенческих паттернов — Наблюдатель (Observer).
Как я уже писал ранее, существует три вида паттернов проектирования:
- Порождающие паттерны позволяют возможность выполнять инициализацию объектов наиболее удобным и оптимальным способом.
- Структурные паттерны описывают взаимоотношения между различными классами или объектами, позволяя им совместно реализовывать поставленную задачу.
- Поведенческие паттерны позволяют грамотно организовать связь между сущностями для оптимизации и упрощения их взаимодействия.
Наблюдатель (Observer) — это поведенческий паттерн, который определяет зависимость между объектами типа «один ко многим» таким образом, что при изменении состояния одного из объектов все зависящие от него оповещаются об этом и при неоходимости автоматически обновляются. То есть, наблюдатель уведомляет все заинтересованные стороны о произошедшем событии или об изменении своего состояния.
Архитектура паттерна Observer
Давайте рассмотрим диаграмму паттерна.

- Observer — определяет интерфейс наблюдателя;
- Subject (наблюдаемый объект) — определяет методы подключения и отключения наблюдателей;
- ConcreteObserver — реализует интерфейс наблюдателя;
- ConcreteSubject — конкретный тип наблюдаемого объекта.
Логика работы паттерна Наблюдатель (Observer)
Рассмотрим основную логику работы паттерна Наблюдатель. Существует два способа взаимодействия между объектами:
- Pull-модель – Объект1 обращается к Объекту2 для выполнения каких-либо операций или получения данных. Соответственно Объект2 выполняет работу по требованию.
- Push-модель – Объект2 уведомляет Объект1 о некотором событии. Соответственно Объект1 обрабатывает событие необходимым образом.
Паттерн Наблюдатель реализует push-модель взаимодействия. Он позволяет уменьшить связанность между основным и зависимыми классами. Обратите внимание, что классическая реализация данного паттерна не используется в языке C#, так как он предоставляет встроенные механизмы событийного взаимодействия объектов, такие делегаты, события (event), интерфейсы IObserver и IObservable. В языках платформы .NET паттерн Наблюдатель чаще всего реализуется с помощью событий. События представляют собой умную оболочку над делегатами, которая позволяет клиентам лишь подписываться на события или отказываться от подписки, а владельцу события — еще и инициировать событие для уведомления всех подписчиков.
Реализация паттерна проектирования Наблюдатель (Observer) на языке C#
Для начала создадим класс Наблюдаемого объекта Subject. В нем объявим событие OnSaved и создадим метод сохранения Save, который будет генерировать событие.
using System; using System.IO; using System.Text; namespace Patterns.Observer { /// <summary> /// Наблюдаемый класс. /// </summary> public class Subject { /// <summary> /// Название наблюдаемого. /// </summary> public string Name { get; set; } /// <summary> /// Событие, генерируемое при сохранении сущности. /// </summary> public event EventHandler OnSaved; /// <summary> /// Создать экземпляр наблюдаемого класса. /// </summary> /// <param name="name">Имя наблюдаемого.</param> public Subject(string name) { if(string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } Name = name; } /// <summary> /// Сохранить наблюдаемый класс. /// </summary> public void Save() { using (StreamWriter sw = new StreamWriter("temp.txt", false, Encoding.Default)) { sw.WriteLine(Name); } // Такая форма записи используется для того, чтобы избежать исключения NullReferenceException, // если нет ни одного подписчика у события. OnSaved?.Invoke(this, EventArgs.Empty); } /// <summary> /// Приведение объекта к строке. /// </summary> /// <returns></returns> public override string ToString() { return Name; } } }
Далее создадим класс наблюдатель Observer, который будет подписан на событие сохранение наблюдаемого объекта и обрабатывать его, выводя на консоль сообщение.
using System; namespace Patterns.Observer { /// <summary> /// Наблюдатель. /// </summary> public class Observer { /// <summary> /// Название. /// </summary> public string Title { get; set; } /// <summary> /// Создать экземпляр наблюдателя. /// </summary> /// <param name="title">Название наблюдателя.</param> /// <param name="subject">Наблюдаемый объект.</param> public Observer(string title, Subject subject) { if(string.IsNullOrEmpty(title)) { throw new ArgumentNullException(nameof(title)); } if(subject == null) { throw new ArgumentNullException(nameof(subject)); } Title = title; subject.OnSaved += SaveSubject; } /// <summary> /// Обработчик события сохранения наблюдаемого объекта. /// </summary> /// <param name="sender">Наблюдаемый объект.</param> /// <param name="e">Аргументы события.</param> private void SaveSubject(object sender, EventArgs e) { string format = "dd.MM.yyyy hh:mm:ss"; Console.WriteLine($"[{DateTime.Now.ToString(format)}] Наблюдатель '{this}': Выполнено сохранение наблюдаемого объекта '{sender}'"); } /// <summary> /// Приведение объекта к строке. /// </summary> /// <returns></returns> public override string ToString() { return Title; } } }
Теперь нам осталось только создать и обратиться объектам в основной части программы.
using System; namespace Observer { public class Program { static void Main(string[] args) { // Создаем наблюдаемый объект. var subject = new Subject("Объект 1"); // Создаем наблюдателя. var observer = new Observer("Наблюдатель 1", subject); // Вызываем метод наблюдаемого объекта, // который создает событие. // Наблюдатель должен отреагировать на событие и // вывести сообщение на консоль. subject.Save(); // Остановимся, чтобы увидеть результат. Console.ReadLine(); } } }
Получаем следующий результат.

Исходный код программы можно посмотреть в репозитории https://github.com/shwanoff/Observer.
Рекомендую также изучить статью Паттерн Абстрактная фабрика (Abstract Factory). А еще подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.