Наблюдатель – паттерн поведения объектов
Назначение
Определяет зависимость типа “один ко многим” между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом и автоматически обновляются
Известен также под именем
Dependents (подчинённые), Publish-Subscribe (издатель-подписчик)
Observer : применимость
• Когда у абстракции есть два аспекта, один из которых зависит от другого. Инкапсуляции этих аспектов в разные объекты позволяют изменять и повторно использовать их независимо.
• Когда при модификации одного объекта требуется изменить другие и вы не знаете, сколько именно объектов нужно изменить.
• Когда один объект должен оповещать других, не делая предположений об уведомляемых объектах. Другими словами, вы не хотите, чтобы объекты были тесно связаны между собой.
Observer : структура
Рисунок 41
Участники
• Subject – субъект - располагает информацией о своих наблюдателях. За субъектом может «следить» любое число наблюдателей;
- предоставляет интерфейс для присоединения и отделения наблюдателей.
• Observer – наблюдатель - определяет интерфейс обновления для объектов, которые должны быть уведомлены об изменении субъекта.
• ConcreteSubject - конкретный субъект - сохраняет состояние, представляющее интерес для конкретного наблюдателя ConcreteObserver
- посылает информацию своим наблюдателям, когда происходит изменение.
• a ConcreteObserver - конкретный наблюдатель - хранит ссылку на объект класса ConcreteSubject;
- сохраняет данные, которые должны быть согласованы с данными субъекта;
- реализует интерфейс обновления, определенный в классе Observer, чтобы поддерживать согласованность с субъектом.
Отношения
• Объект ConcreteSubject уведомляет своих наблюдателей о любом изменении, которое могло бы привести к рассогласованности состояний наблюдателя и субъекта;
• После получения от конкретного субъекта уведомления об изменении объект ConcreteObserver может запросить у субъекта дополнительную информацию, которую использует для того, чтобы оказаться в состоянии, согласованном с состоянием субъекта.
На диаграмме взаимодействий показаны отношения между субъектом и двумя наблюдателями.
Observer : отношения
Рисунок 42
Отметим, что объект Observer, который инициирует запрос на изменение, откладывает свое обновление до получения уведомления от субъекта. Операция Notify не всегда вызывается субъектом. Ее может вызвать и наблюдатель, и посторонний объект.
Observer : результаты
• Абстрактная связанность субъекта и наблюдателя. Субъект имеет информацию лишь о том, что у него есть ряд наблюдателей, каждый из которых подчиняется простому интерфейсу абстрактного класса Observer. Субекту неизвестны конкретные классы наблюдателей. Таким образом, связи между субъектами и наблюдателями носят абстрактный характер и сведены к минимуму. Поскольку субъект и наблюдатель не являются тесно связанными, то они могут находиться на разных уровнях абстракции системы. Субъект более низкого уровня может уведомлять наблюдателей, находящихся на верхних уровнях, не нарушая иерархии системы. Если бы субъект и наблюдатель представляли собой единое целое, то получающийся объект либо пересекал бы границы уровней (нарушая принцип их формирования), либо должен был находиться на каком-то одном уровне (компрометируя абстракцию уровня).
• Поддержка широковещательных коммуникаций. В отличие от обычного запроса для уведомления, посылаемого субъектом, не нужно задавать определенного получателя. Уведомление автоматически поступает всем подписавшимся на него объектам. Субъекту не нужна информация о количестве таких объектов, от него требуется всего лишь уведомить своих наблюдателей. Поэтому мы можем в любое время добавлять и удалять наблюдателей. Наблюдатель сам решает, обработать полученное уведомление или игнорировать его.
• Неожиданные обновления. Поскольку наблюдатели не располагают информацией друг о друге, им неизвестно и о том, во что обходится изменение субъекта. Безобидная, на первый взгляд, операция над субъектом может вызвать целый ряд обновлений наблюдателей и зависящих от них объектов. Более того, нечетко определенные или плохо поддерживаемые критерии зависимости могут стать причиной непредвиденных обновлений, отследить которые очень сложно. Эта проблема усугубляется еще и тем, что простой протокол обновления не содержит никаких сведений о том, что именно изменилось в субъекте. Без дополнительного протокола, помогающего выяснить характер изменений, наблюдатели будут вынуждены проделать сложную работу для косвенного получения такой информации.
Observer : реализация
• Отображение субъектов на наблюдателей. С помощью этого простейшего способа субъект может отследить всех наблюдателей, которым он должен посылать уведомления, то есть хранить на них явные ссылки. Однако при наличии большого числа субъектов и всего нескольких наблюдателей это может оказаться накладно. Один из возможных компромиссов в пользу экономии памяти за счет времени состоит в том, чтобы использовать ассоциативный массив (например, хэш-таблицу) для хранения отображения между субъектами и наблюдателями. Тогда субъект, у которого нет наблюдателей, не будет зря расходовать память. С другой стороны, при таком подходе увеличивается время поиска наблюдателей.
• Наблюдение более чем за одним субъектом. Иногда наблюдатель может зависеть более чем от одного субъекта. Например, у электронной таблицы бывает более одного источника данных. В таких случаях необходимо расширить интерфейс Update, чтобы наблюдатель мог «узнать», какой субъект прислал уведомление. Субъект может просто передать себя в качестве параметра операции Update, тем самым сообщая наблюдателю, что именно нужно обследовать.
• Кто инициатор обновления. Чтобы сохранить согласованность, субъект и его наблюдатели полагаются на механизм уведомлений. Но какой именно объект вызывает операцию-Notify для инициирования обновления? Есть два варианта:
- операции класса Subject, изменившие состояние, вызывают Notifу для уведомления об этом изменении. Преимущество такого подхода в том, что клиентам не надо помнить о необходимости вызывать операцию Notify субъекта. Недостаток же заключается в следующем: при выполнении каждой из нескольких последовательных операций будут производиться обновления, что может стать причиной неэффективной работы программы;
- ответственность за своевременный вызов Notify возлагается на клиента. Преимущество: клиент может отложить инициирование обновления до завершения серии изменений, исключив тем самым ненужные промежуточные обновления. Недостаток: у клиентов появляется дополнительная обязанность. Это увеличивает вероятность ошибок, поскольку клиент может забыть вызвать Notify.
• Как избежать зависимости протокола обновления от наблюдателя: модели вытягивания и проталкивания. В реализациях паттерна наблюдатель субъект довольно часто транслирует всем подписчикам дополнительную информацию о характере изменения. Она передается в виде аргумента операции Update, и объем ее меняется в широких диапазонах. На одном полюсе находится так называемая модель проталкивания (push model), когда субъект посылает наблюдателям детальную информацию об изменении независимо от того, нужно ли им это. На другом - модель вытягивания (pull model), когда субъект не посылает ничего, кроме минимального уведомления, а наблюдатели запрашивают детали позднее. В модели вытягивания подчеркивается неинформированность субъекта о своих наблюдателях, а в модели проталкивания предполагается, что субъект владеет определенной информацией о потребностях наблюдателей. В случае применения модели проталкивания степень повторного их использования может снизиться, так как классы Subject предполагают о классах Observer, которые не всегда могут быть верны. С другой стороны, модель вытягивания может оказаться неэффективной, ибо наблюдателям без помощи субъекта необходимо выяснять, что изменилось.
• Явное специфицирование представляющих интерес модификаций. Эффективность обновления можно повысить, расширив интерфейс регистрации субъекта, то есть предоставив возможность при регистрации наблюдателя указать, какие события его интересуют. Когда событие происходит, субъект информирует лишь тех наблюдателей, которые проявили к нему интерес.
Применение в Java API
Модель делегирования событий в языке Java – это специальная форма шаблона Observer.
Паттерн State.
Дата: 2019-02-25, просмотров: 269.