Наблюдатель (Observer) — различия между версиями

Материал из Вики ИТ мехмата ЮФУ
Перейти к: навигация, поиск
(Назначение)
(Варианты)
 
(не показано 10 промежуточных версий этого же участника)
Строка 8: Строка 8:
  
 
=== Описание ===
 
=== Описание ===
 +
В системе, в которой одни объекты зависят от других, необходимо согласованное обновление информации.
 +
 +
Ключевыми в паттерне Наблюдатель являются '''Субъект''' и '''Наблюдатель'''. У Субъекта может быть сколько угодно зависимых от него наблюдателей.
 +
 +
Все наблюдатели уведомляются об изменениях в состоянии субъекта. Получив уведомление, наблюдатель опрашивает Субъекта с тем чтобы синхронизировать с ним своё состояние.
 +
 +
=== Использование ===
 +
* Когда у абстракции есть два аспекта, один из которых зависит от другого.
 +
* Когда при модификации одного объекта требуется изменить единым образом неизвестное количество других объектов.
 +
* Когда нужно разорвать жесткую связь между связанными объектами, один из которых зависит от другого
  
 
=== Реализация ===
 
=== Реализация ===
Строка 14: Строка 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()
[[Изображение:.png]]
+
    {
 +
        observerState = Subject.SubjectState;
 +
    }
  
=== Пример ===
+
    public ConcreteSubject Subject
 +
    {
 +
        get; set;
 +
    }
 +
}
 +
</source>
  
 
=== Достоинства и недостатки ===
 
=== Достоинства и недостатки ===
*  
+
* Минимальная связанность субъекта и наблюдателя: субъект знает лишь о том, что у него есть ряд наблюдателей с простым интерфейсом Update()
 +
* Широковещательность оповещения: субъект оповещает не конкретного, а всех подписанных на него наблюдателей
 +
* Непредвиденные обновления. Изменение субъекта может вызвать каскад зависимых от него наблюдателей с высокой стоимостью обновления.
 +
* Протокол обновления не содержит никаких сведений о том, что изменилось в субъекте - работа наблюдателей при этом усложняется.
  
 
=== Варианты ===
 
=== Варианты ===
*
+
* Много субъектов - несколько наблюдателей. Вводится дополнительный объект (ассоциативный массив) для хранения отображения между субъектами и наблюдателями. Тогда субъекты, не имеющие наблюдателей, не расходуют память.
 +
* Можно инкапсулировать сложную семантику обновления в классе changeManager (менеджер изменений).
 +
* Наблюдатель может наблюдать более чем за одним субъектом. Тогда надо расширить интерфейс Update(), передав ему в качестве параметра субъект
 +
* Удаление субъекта должно сопровождаться передачей специальных сообщений своим наблюдателям чтобы они могли вовремя уничтожить ссылку на наблюдателя.
 +
* Субъект может передавать наблюдателям информацию о характере изменений в качестве параметра метода Update. Информация может быть как полной (большие объёмы), так и частичной, вынуждающей наблюдателей посылать дополнительные запросы субъекту для выяснения деталей.
 +
* При регистрации Наблюдателя он может подписаться у субъекта только на определенные события. Тип события передается дополнительным параметром в методе Attach.

Текущая версия на 09:33, 22 июля 2014

К основной странице курса

Другое имя

Издатель-Подписчик (Publisher-Subscriber)

Назначение

При изменении состояния одного объекта все зависимые от него объекты (подписчики) оповещаются об обновлении.

Описание

В системе, в которой одни объекты зависят от других, необходимо согласованное обновление информации.

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

Все наблюдатели уведомляются об изменениях в состоянии субъекта. Получив уведомление, наблюдатель опрашивает Субъекта с тем чтобы синхронизировать с ним своё состояние.

Использование

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

Реализация

Диаграмма классов

ObserverCommon.png

Участники

  • 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.