Наблюдатель (Observer) — различия между версиями
Материал из Вики ИТ мехмата ЮФУ
Admin (обсуждение | вклад) (→Диаграмма классов) |
Admin (обсуждение | вклад) (→Варианты) |
||
(не показано 11 промежуточных версий этого же участника) | |||
Строка 1: | Строка 1: | ||
[[Страница_курса_Паттерны_проектирования| К основной странице курса]] | [[Страница_курса_Паттерны_проектирования| К основной странице курса]] | ||
__NOTOC__ | __NOTOC__ | ||
+ | ===Другое имя=== | ||
+ | Издатель-Подписчик (Publisher-Subscriber) | ||
+ | |||
=== Назначение === | === Назначение === | ||
+ | При изменении состояния одного объекта все зависимые от него объекты (подписчики) оповещаются об обновлении. | ||
=== Описание === | === Описание === | ||
+ | В системе, в которой одни объекты зависят от других, необходимо согласованное обновление информации. | ||
+ | |||
+ | Ключевыми в паттерне Наблюдатель являются '''Субъект''' и '''Наблюдатель'''. У Субъекта может быть сколько угодно зависимых от него наблюдателей. | ||
+ | |||
+ | Все наблюдатели уведомляются об изменениях в состоянии субъекта. Получив уведомление, наблюдатель опрашивает Субъекта с тем чтобы синхронизировать с ним своё состояние. | ||
+ | |||
+ | === Использование === | ||
+ | * Когда у абстракции есть два аспекта, один из которых зависит от другого. | ||
+ | * Когда при модификации одного объекта требуется изменить единым образом неизвестное количество других объектов. | ||
+ | * Когда нужно разорвать жесткую связь между связанными объектами, один из которых зависит от другого | ||
=== Реализация === | === Реализация === | ||
Строка 10: | Строка 24: | ||
==== Участники==== | ==== Участники==== | ||
− | * | + | * Subject - субъект |
+ | ** Хранит список своих наблюдателей | ||
+ | ** Предоставляет интерфейс для присоединения и отсоединения наблюдателей | ||
+ | ** Имеет метод оповещения всех подписанных на него наблюдателей | ||
+ | * Observer - наблюдатель | ||
+ | ** Определяет метод Update() для обновления состояния потомков наблюдателя | ||
+ | * ConcreteSubject - конкретный субъект | ||
+ | ** Имеет состояние, представляющее интерес дял конкретного наблюдателя | ||
+ | ** Посылает информацию наблюдателям, когда происходит изменение | ||
+ | * ConcreteObserver - конкретный наблюдатель | ||
+ | ** Хранит ссылку на своего субъекта, за изменением состояния которого он следит. | ||
+ | ** Сохраняет на своей стороне данные, которые должны быть согласованы с данными субъекта | ||
+ | ** Реализует метод Update() | ||
+ | |||
+ | === Код === | ||
+ | <source lang="Csharp">abstract class Subject | ||
+ | { | ||
+ | List<Observer> observers = new List<Observer>(); | ||
+ | |||
+ | public void Attach(Observer observer) | ||
+ | { | ||
+ | observers.Add(observer); | ||
+ | } | ||
+ | |||
+ | public void Detach(Observer observer) | ||
+ | { | ||
+ | observers.Remove(observer); | ||
+ | } | ||
+ | |||
+ | public void Notify() | ||
+ | { | ||
+ | foreach (var o in observers) | ||
+ | o.Update(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class ConcreteSubject : Subject | ||
+ | { | ||
+ | public string SubjectState | ||
+ | { | ||
+ | get; set; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | abstract class Observer | ||
+ | { | ||
+ | public abstract void Update(); | ||
+ | } | ||
+ | |||
+ | class ConcreteObserver : Observer | ||
+ | { | ||
+ | string observerState; | ||
+ | |||
+ | public ConcreteObserver(ConcreteSubject subject) | ||
+ | { | ||
+ | this.Subject = subject; | ||
+ | } | ||
− | = | + | public override void Update() |
− | + | { | |
+ | observerState = Subject.SubjectState; | ||
+ | } | ||
− | + | public ConcreteSubject Subject | |
+ | { | ||
+ | get; set; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
=== Достоинства и недостатки === | === Достоинства и недостатки === | ||
− | * | + | * Минимальная связанность субъекта и наблюдателя: субъект знает лишь о том, что у него есть ряд наблюдателей с простым интерфейсом Update() |
+ | * Широковещательность оповещения: субъект оповещает не конкретного, а всех подписанных на него наблюдателей | ||
+ | * Непредвиденные обновления. Изменение субъекта может вызвать каскад зависимых от него наблюдателей с высокой стоимостью обновления. | ||
+ | * Протокол обновления не содержит никаких сведений о том, что изменилось в субъекте - работа наблюдателей при этом усложняется. | ||
=== Варианты === | === Варианты === | ||
− | * | + | * Много субъектов - несколько наблюдателей. Вводится дополнительный объект (ассоциативный массив) для хранения отображения между субъектами и наблюдателями. Тогда субъекты, не имеющие наблюдателей, не расходуют память. |
+ | * Можно инкапсулировать сложную семантику обновления в классе changeManager (менеджер изменений). | ||
+ | * Наблюдатель может наблюдать более чем за одним субъектом. Тогда надо расширить интерфейс Update(), передав ему в качестве параметра субъект | ||
+ | * Удаление субъекта должно сопровождаться передачей специальных сообщений своим наблюдателям чтобы они могли вовремя уничтожить ссылку на наблюдателя. | ||
+ | * Субъект может передавать наблюдателям информацию о характере изменений в качестве параметра метода Update. Информация может быть как полной (большие объёмы), так и частичной, вынуждающей наблюдателей посылать дополнительные запросы субъекту для выяснения деталей. | ||
+ | * При регистрации Наблюдателя он может подписаться у субъекта только на определенные события. Тип события передается дополнительным параметром в методе Attach. |
Текущая версия на 09:33, 22 июля 2014
Другое имя
Издатель-Подписчик (Publisher-Subscriber)
Назначение
При изменении состояния одного объекта все зависимые от него объекты (подписчики) оповещаются об обновлении.
Описание
В системе, в которой одни объекты зависят от других, необходимо согласованное обновление информации.
Ключевыми в паттерне Наблюдатель являются Субъект и Наблюдатель. У Субъекта может быть сколько угодно зависимых от него наблюдателей.
Все наблюдатели уведомляются об изменениях в состоянии субъекта. Получив уведомление, наблюдатель опрашивает Субъекта с тем чтобы синхронизировать с ним своё состояние.
Использование
- Когда у абстракции есть два аспекта, один из которых зависит от другого.
- Когда при модификации одного объекта требуется изменить единым образом неизвестное количество других объектов.
- Когда нужно разорвать жесткую связь между связанными объектами, один из которых зависит от другого
Реализация
Диаграмма классов
Участники
- Subject - субъект
- Хранит список своих наблюдателей
- Предоставляет интерфейс для присоединения и отсоединения наблюдателей
- Имеет метод оповещения всех подписанных на него наблюдателей
- Observer - наблюдатель
- Определяет метод Update() для обновления состояния потомков наблюдателя
- ConcreteSubject - конкретный субъект
- Имеет состояние, представляющее интерес дял конкретного наблюдателя
- Посылает информацию наблюдателям, когда происходит изменение
- ConcreteObserver - конкретный наблюдатель
- Хранит ссылку на своего субъекта, за изменением состояния которого он следит.
- Сохраняет на своей стороне данные, которые должны быть согласованы с данными субъекта
- Реализует метод Update()
Код
abstract class Subject
{
List<Observer> observers = new List<Observer>();
public void Attach(Observer observer)
{
observers.Add(observer);
}
public void Detach(Observer observer)
{
observers.Remove(observer);
}
public void Notify()
{
foreach (var o in observers)
o.Update();
}
}
class ConcreteSubject : Subject
{
public string SubjectState
{
get; set;
}
}
abstract class Observer
{
public abstract void Update();
}
class ConcreteObserver : Observer
{
string observerState;
public ConcreteObserver(ConcreteSubject subject)
{
this.Subject = subject;
}
public override void Update()
{
observerState = Subject.SubjectState;
}
public ConcreteSubject Subject
{
get; set;
}
}
Достоинства и недостатки
- Минимальная связанность субъекта и наблюдателя: субъект знает лишь о том, что у него есть ряд наблюдателей с простым интерфейсом Update()
- Широковещательность оповещения: субъект оповещает не конкретного, а всех подписанных на него наблюдателей
- Непредвиденные обновления. Изменение субъекта может вызвать каскад зависимых от него наблюдателей с высокой стоимостью обновления.
- Протокол обновления не содержит никаких сведений о том, что изменилось в субъекте - работа наблюдателей при этом усложняется.
Варианты
- Много субъектов - несколько наблюдателей. Вводится дополнительный объект (ассоциативный массив) для хранения отображения между субъектами и наблюдателями. Тогда субъекты, не имеющие наблюдателей, не расходуют память.
- Можно инкапсулировать сложную семантику обновления в классе changeManager (менеджер изменений).
- Наблюдатель может наблюдать более чем за одним субъектом. Тогда надо расширить интерфейс Update(), передав ему в качестве параметра субъект
- Удаление субъекта должно сопровождаться передачей специальных сообщений своим наблюдателям чтобы они могли вовремя уничтожить ссылку на наблюдателя.
- Субъект может передавать наблюдателям информацию о характере изменений в качестве параметра метода Update. Информация может быть как полной (большие объёмы), так и частичной, вынуждающей наблюдателей посылать дополнительные запросы субъекту для выяснения деталей.
- При регистрации Наблюдателя он может подписаться у субъекта только на определенные события. Тип события передается дополнительным параметром в методе Attach.