1. Определение режима наблюдателя:
Режим наблюдателя также называется режим подписки-публикации, в котором целевой объект управляет всеми объектами наблюдателя, зависящими от него и активно выпускает уведомления при изменении его состояния. Это обычно достигается путем вызова методов каждого наблюдателя. Этот шаблон обычно используется в системах обработки событий.
1. Общая структура схемы наблюдателя
Во -первых, давайте посмотрим на описание схемы наблюдателя:
Роли режима наблюдателя следующие:
Тема (абстрактная тема интерфейса): определяет серию операций в списке наблюдателей в классе темы, включая сложение, удаление, уведомление и т. Д.
Конкретный предмет (конкретный тематический класс):
Наблюдатель (Abstract Observer Interface): определяет наблюдатель, чтобы принять операции в статусе обновления темы класса.
ConceteObserver (конкретный класс наблюдателей): реализует логику, такую как обновление тематических уведомлений класса, интерфейсом Observer.
На этой классной диаграмме мы видим, что класс темы поддерживает список классов, который реализует интерфейс наблюдателя. Тематический класс использует этот список для выполнения серии дополнений, удалений и модификаций на наблюдателе. Класс наблюдателя также может активно вызвать метод обновления, чтобы понять информацию об обновлении статуса класса темы.
Приведенные выше классовые диаграммы описывают только основную идею образца наблюдателя, и есть много недостатков. Например, как наблюдатель, вы также можете активно подписаться на определенные темы и т. Д. Следующие примеры внесут некоторые изменения для применения конкретной бизнес -логики.
2. Пример режима наблюдателя
Мы строим наблюдатель и тематический класс, где наблюдатели могут активно подписаться на темы или отменить темы. Категория темы равномерно управляется менеджером темы. Ниже приведена классная диаграмма:
Предмет:
Общественный интерфейс субъект {// зарегистрировать общедоступный реестр void (наблюдатель наблюдателя); // Удалить наблюдатель public void удалить (наблюдатель наблюдателя); // Уведомление всех наблюдателей public void notifyObservers (); // Получить сообщение, которое будет опубликовано с помощью тематического класса public String getMessage ();} concertesubject: открытый класс MySubject реализует субъект {private list <baserver> наблюдателей; Частный логический изменился; Приватное строковое сообщение; // блокировка объекта, используемая для синхронного обновления списка наблюдателей за частным конечным объектом mutex = new Object (); public mySubject () {stemvers = new ArrayList <Searnver> (); Изменен = false; } @Override public void Register (Observer Observer) {if (stemver == null) бросить новый NullPointerException (); // Сертифицируют не повторять if (! Stairvers.contains (stemver)) наблюдателей. Add (Observer); } @Override public void remove (stemver stemver) {exervers.remove (stemver); } @Override public void notifyObservers () {// Список температуры <exerver> tempobservers = null; синхронизированный (mutex) {if (! Изменен) return; tempobservers = new ArrayList <> (this.observers); this.changed = false; } for (stemver obj: tempobservers) {obj.update (); }} // класс темы публикует новое сообщение public void makeChanged (String Message) {System.out.println («Субъект делает изменение:» + message); this.message = сообщение; this.changed = true; notifyObservers (); } @Override public String getMessage () {return this.message; }}Когда Concertesubject делает обновление, все наблюдатели в списке уведомляются, и метод обновления наблюдателя вызывается для реализации логики после получения уведомления. Обратите внимание на блок синхронизации в notifyobservers здесь. В случае многопоточного, чтобы избежать добавления и удаления списка наблюдателей другими потоками при публикации уведомлений в тематическом классе, в блоке синхронизации используется временный список для получения текущего списка наблюдателей.
Управление субъектом: менеджер тематического класса
Общедоступный класс субъект Management {// Имя записи - MAP Private Map <String, субъект> субъект lists = new Hashmap <String, subject> (); public void AddSubject (имя строки, субъект субъекта) {subjectList.put (имя, субъект); } public void addSubject (субъект субъекта) {субъект list.put (subject.getClass (). getName (), субъект); } public subject getSubject (строка субъекта name) {return subjectlist.get (subjectName); } public void removEsubject (string name, субъект субъекта) {} public void removEsubject (субъект субъекта) {} // singleton private subjectmanagement () {} public static subjectmanagement getInstance () {return subjectManagementInstance.instance; } Частный статический класс субъект управления instance {static final Encancemangemancement = New SubjectManagement (); }}Цель менеджера темы - получить объект экземпляра темы, когда наблюдатель подписывается на тему.
Наблюдатель:
Общественный интерфейс stemver {public void update (); public void setSubject (субъект субъекта);} concerteObserver: открытый класс myobserver реализует наблюдатель {частный субъект; // Получить сообщение уведомления от субъекта @Override public void update () {string message = subject.getMessage (); System.out.println ("from subject" + subject.getClass (). GetName () + "Сообщение:" + Message); } @Override public void setSubject (субъект субъекта) {this.subject = субъект; } // subcirbe некоторые предметы public void Подписка (String subjectName) {subjectManagement.getInStance (). getSubject (субъект имени) .register (this); } // Отмена подписывания public void cancelsubScribe (String subjectName) {subjectManagement.getInstance (). getSubject (subjectName) .Remove (this); }} Тест: мы абстрагируем классы темы и наблюдатели за писателями и читателями
Public Class ObserVertest {Private Static MySubject Writer; @Beforeclass public static void setupbeForeClass () бросает исключение {writer = new mySubject (); // Добавить писателя по имени Linus subjectManagement.getInstance (). AddSubject ("Linus", писатель); } @Test public void test () {// определить несколько читателей myobserver reader1 = new myobserver (); Myobserver reader2 = new myobserver (); Myobserver reader3 = new myobserver (); reader1.setsubject (писатель); reader2.setsubject (писатель); reader3.setsubject (писатель); reader1.subscribe ("linus"); reader2.subscribe ("linus"); reader3.subscribe ("linus"); writer.makeChanged («У меня новое изменилось»); reader1.update (); }}Вышеуказанное является небольшим примером образца наблюдателя. Можно видеть, что каждый тематический класс должен поддерживать соответствующий список наблюдателей. Здесь мы можем дополнительно абстрагировать, основываясь на абстрактном уровне конкретной темы, поместить это собрание в абстрактный класс, чтобы совместно поддерживать список. Конечно, конкретная операция зависит от фактической бизнес -логики.
2. Слушатель в сервлете
Давайте поговорим о слушателе в Сервлете, давайте поговорим о другой форме модели наблюдателя - модели, управляемой событиями. Как и роль тематического шаблона наблюдателя, упомянутая выше, модель, управляемая событиями, включает в себя источники событий, конкретные события, слушатели и конкретные слушатели.
Слушатель в Сервлете-типичная модель, управляемая событиями.
В JDK есть набор классов, управляемых событиями, в том числе унифицированный интерфейс слушателя и унифицированный источник событий. Исходный код заключается в следующем:
/*** Интерфейс тега, который должен расширять все интерфейсы прослушивателя событий. * @since jdk1.1 */public interface EventListener {}Это интерфейс флага, и JDK предусматривает, что все слушатели должны наследовать этот интерфейс.
открытый класс EventObject реализует java.io.serializable {Private Static Final Long SerialVersionUID = 5516075349620653480L; /*** объект, на котором изначально произошло событие. */ защищенный источник переходного объекта; /*** Создает прототип. * * @param Source объект, на котором изначально произошло событие. * @Exception allogalargumentException, если источник нулевой. */ public EventObject (Object Source) {if (Source == null) бросить new allogalargumentException ("null source"); this.source = source; } /*** объект, на котором изначально произошло событие. * * @return Объект, на котором изначально произошло событие. */ public Object getSource () {return Source; } /*** Возвращает строковое представление этого события. * * @return A Строковое представление этого события. */ public String toString () {return getClass (). getName () + "[source =" + source + "]"; }}Venobject - это единый источник событий, указанный JDK. Класс ровнообъекта определяет источник события и метод получить метод получения источника события.
Давайте проанализируем процесс работы слушателя сервлета.
1. Композиция слушателя сервлета
В настоящее время существует 6 типов интерфейсов слушателя для двух типов событий в сервлетах, как показано на рисунке ниже:
Конкретная ситуация триггера заключается в следующем:
2. Конкретный процесс запуска слушателя
Давайте возьмем ServletRequestatTributeListener в качестве примера для анализа процесса, управляемого событиями здесь.
Прежде всего, когда httpservletrequest вызывает метод Setattrilbute, он фактически называется org.apache.catalina.connector.request#setattrilbute метод. Давайте посмотрим на его исходный код:
public void setattribute (string name, value value) {... // Приведенный выше логический код был опущен // Здесь слушатель уведомляет об уведомлении о (имя, значение, OldValue); }Ниже приведен исходный код notifyattribiteAssigned (имя строки, значение объекта, объект OldValue)
private void notifyattribiteAssigned (имя строки, значение объекта, объект OldValue) {// Получить объект экземпляра прослушивателя, определенного в веб -приложении от слушателей объекта контейнера [] = context.getApplicationEventListeners (); if ((слушатели == null) || (слушатели.length == 0)) {return; } boolean заменил = (OldValue! = NULL); // Создание связанного объекта события ServletRequestatTtributeVent event = null; if (заменен) {event = new ServletRequestattributeVent (context.getServletContext (), getRequest (), name, oldValue); } else {event = new servletRequestattributevent (context.getServletContext (), getRequest (), name, value); } // спокойствие через все списки слушателей и найти слушателя для соответствующего события для (int i = 0; i <Слушатели. } // Вызов метода прослушивателя для реализации операции прослушивания ServletRequestattribiteListener Slister = (ServletRequestattributeListener) слушатели [i]; try {if (reply) {aslieder.attributeRedced (event); } else {aslieder.attributeadded (event); }} catch (throwable t) {exceptionUtils.handlethrowable (t); context.getLogger (). error (sm.getString ("coyoteRequest.attributeevent"), t); // Ошибка клапана поднимет это исключение и отобразит его на attributes attributes.put (requestDispatcher.error_exception, t); }}}Приведенный выше пример четко показывает, как называется ServletRequestatTribetElistener. Пользователям нужно только реализовать интерфейс прослушивателя. Слушатели в сервлетах почти охватывают события, которые вас интересуют на протяжении всего жизненного цикла сервлета. Гибкое использование этих слушателей может сделать программу более гибкой.
3. Комплексные примеры
Например, если вы смотрели фильмы «Полиция и гангстеры» TVB, вы узнаете, как работает под прикрытием. Как правило, у полицейского может быть несколько тайных агентов, которые пробираются к врагу и узнают о информации. Агент под прикрытием полностью работает на инструкциях своего лидера. Лидер говорит, каким действием он должен следовать. Если время действия изменится, он должен немедленно изменить время, которое он сотрудничает с действием. Если лидер посылает двух тайных агентов, чтобы вторгаться в врага, то лидер эквивалентен абстрактной теме. Инспектор Чжан Сан отправил двух тайных агентов Ли Си и Ван Ван Ву. Чжан Сан эквивалентен конкретной теме, а агент под прикрытием эквивалентен абстрактному наблюдателю. Этими двумя тайными агентами являются Li Si и Wang Wu, которые являются конкретными наблюдателями. Действие расследования эквивалентно наблюдателю, регистрирующему субъект. Тогда эта классовая диаграмма выглядит следующим образом:
Использование Java API для реализации описания кода следующим образом:
пакетный наблюдатель; импортировать java.util.list; импортировать java.util.observable; импортировать java.util.observable; / ***Описание: Полиция Чжан Сан*/ Полиция общественного класса расширяет наблюдаемое {частное строковое время; общественная полиция (список <baserver> list) {super (); для (наблюдатель O: List) {AddObserver (O); }} public void изменение (строка времени) {this.time = time; setChanged (); notifyObservers (this.Time); }} пакетный наблюдатель; импортировать java.util.observable; импортировать java.util.observer; / **! @Override public void update (наблюдаемая o, object arg) {time = (string) arg; System.out.println («раскрыть полученное сообщение, а время действия:»+время); }} пакетный наблюдатель; импортировать java.util.observable; импортировать java.util.observer; / **. @Override public void update (наблюдаемая o, object arg) {time = (string) arg; System.out.println («Раскрыть B получил сообщение, и время действия было:»+время); }} пакетный наблюдатель; импортировать java.util.arraylist; импортировать java.util.list; импортировать java.util.observer; / **! Undercoverb o2 = new Undercoverb (); List <Beaserver> list = new ArrayList <> (); list.add (o1); list.add (O2); Субъект полиции = новая полиция (список); Subject.Change ("02:25"); System.out.println ("======================= Из -за обнаруженной информации время действия Advanced ======================================================================================================================== Результаты тестового прогона:
Под прикрытием B получил сообщение, и время действия: 02:25 под прикрытием A получил сообщение, а время действия: 02:25 ================
4. Резюме
Паттерн наблюдателя определяет взаимосвязь между объектами. Когда состояние объекта (наблюдателя) изменяется, объекты, которые зависят от него, будут уведомлены. Он может быть применен для публикации-подписки, изменений-афудий в таких бизнес-сценариях.
Наблюдатель использует свободный метод связи. Наблюдатель не знает деталей наблюдателя, но только знает, что наблюдатель реализовал интерфейс.
Модель, управляемая событиями, более гибкая, но она также оплачивает стоимость сложности системы, потому что мы должны настроить слушателя и событие для каждого источника событий, что увеличит бремя для системы.
Ядро модели наблюдателя состоит в том, чтобы сначала отличить роль и позиционировать наблюдателя и наблюдателя, и они являются отношениями между ними. Ключом к реализации является установление связи между наблюдателем и наблюдателем. Например, в классе наблюдателя существует набор, который используется для хранения наблюдателя, и все наблюдатели должны быть уведомлены при изменении обнаруженной вещи. В конструкторе наблюдателя он будет передаваться наблюдателем, а также зарегистрируется в списке наблюдателей, принадлежащих наблюдателю, то есть в списке наблюдателей.
1. Преимущества режима наблюдателя:
(1) Абстрактные темы полагаются только на абстрактные наблюдатели (2) Режим наблюдателя поддерживает передача связи (3) Режим наблюдателя разделяет слой генерации информации, а уровень ответа.
2. Недостатки режима наблюдателя:
(1) Если тема зарегистрирована большим количеством наблюдателей, она будет стоить более высокой цене, чтобы уведомить всех наблюдателей (2), если метод ответа некоторых наблюдателей заблокирован, весь процесс уведомления будет заблокирован, и другие наблюдатели не могут быть уведомлены во времени.