Паттерн «Наблюдатель». Описание и примеры на C# и Java

Паттерн «Наблюдатель» (Observer) — определяет отношение «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него объекты получают уведомление об этом и также обновляют своё состояние [1].

Работу этого паттерна можно проиллюстрировать на примере подписки на газету или журнал. Как только выходит новый номер, его экземпляры распространяются между подписчиками.

Вероятно, из-за этого данный паттерн по ошибке часто фигурирует в различных источниках под другим названием – «Издатель – Подписчик» (Publisher-Subscriber). Эти паттерны очень похожи, но имеют одно очень важное отличие. В паттерне «Издатель — Подписчик» «издатель» и «подписчик» никак не связаны между собой в коде программы [3], в то время как конкретные участники паттерна « Наблюдатель» имеют такую связь.

Структура паттерна

Паттерн «Наблюдатель» состоит из следующих участников:

Субъект (Subject)Знает о своих наблюдателях и предоставляет интерфейс для и присоединения и отсоединения. За одним субъектом может следить произвольное количество наблюдателей;

Наблюдатель (Observer) определяет интерфейс обновления для объектов, которые должны быть уведомлены о состоянии субъекта;

Конкретный субъект (ConcreteSubject)сохраняет состояние, представляющее интерес для наблюдателей, и отправляет им уведомления в случае его изменения;

Конкретный наблюдатель (ConcreteObserver)хранит ссылку на объект конкретного субъекта. Сохраняет данные, которые должны быть согласованы с данными субъекта. Также реализует интерфейс обновления, который определён наблюдателем.

Наглядно структура паттерна показана на рисунке ниже:

Паттерн Наблюдатель диаграмма

Теперь, когда мы ознакомились с назначением и структурой паттерна «Наблюдатель», самое время рассмотреть его работу на конкретных примерах. Для написания демонстрационных программ используем языки программирования C# и Java.

Пример на C#

Реализуем паттерн «Наблюдатель» на основе приведённого нами ранее примера с подпиской на периодические издания.

Создадим абстрактный класс субъекта:

В качестве конкретного субъекта будет выступать класс моделирующий журнал.

Этот класс имеет свойство, которое хранит текущий номер журнала. Когда это свойство изменяется («вышел новый номер»), его значение передаётся экземплярам класса моделирующего подписчика (конкретного наблюдателя).

Интерфейс IObserver (наблюдатель), который реализует данный класс, содержит всего один метод Update, который принимает в качестве параметра номер журнала.

Далее приведём текст программы, которая иллюстрирует работу паттерна «Наблюдатель» на основе разработанной нами только что объектной модели. Работа программы описана в комментариях в её коде.

Пример на Java

Теперь попробуем написать такую же программу на Java.

Абстрактный класс субъекта:

Интерфейс наблюдателя:

Класс журнала (конкретный субъект):

Класс подписчика (конкретный наблюдатель):

Всё вместе:

Область применения

Паттерн «Наблюдатель» целесообразно использовать в случае если: [2]

  • Существует, как минимум, один объект, рассылающий сообщения и не менее одного получателя сообщений, причём их количество и состав могут изменяться во время работы приложения;
  • Нет надобности очень сильно связывать взаимодействующие объекты, что полезно для повторного использования;
  • Для отправителя сообщений не имеет значения, что делают получатели с предоставленной им информацией.

Паттерн «Наблюдатель» также позволяет значительно повысить гибкость программной системы, так как позволяет в зависимости от задачи легко изменить алгоритмы её работы просто изменив «наблюдатель».

Данная особенность паттерна также положительно влияет и на масштабирование системы. В частности, в зависимости от нагрузки, можно добавлять новые «наблюдатели» или наоборот их отсоединять. Однако такая архитектурная модель не пользуется большой популярностью, вследствие того, что наличие коде программы жесткой связи между участниками паттерна «Наблюдатель», не позволяет достичь показателей, которые доступны в случае использования паттерна «Издатель- Подписчик».

Поэтому в крупных много компонентных системах его применение оправдано только внутри её отдельных «монолитных» составляющих.

Наиболее широкое распространение получила реализация паттерна «Наблюдатель» в формате, так называемых, событий. На её основе построены все GUI библиотеки, а также многие другие программные решения (например, событие поступления данных по сетевому интерфейсу).

Источники

  1. Гамма Э., Хелм Р., Джонсон Р., Влиссидес Дж. Приёмы объектно-ориентированного проектирования. Паттерны проектирования;
  2. Наблюдатель (шаблон проектирования). Википедия;
  3. Издатель-подписчик (шаблон проектирования). Википедия.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *