Паттерн наблюдателя — это шаблон поведенческого проектирования. Использование шаблона Observer используется в тех случаях, когда вас интересует состояние объекта и вы хотите получать уведомления каждый раз, когда оно изменяется. В шаблоне наблюдателя объект, наблюдающий за состоянием другого объекта, называется наблюдателем, а наблюдаемый объект — субъектом. Согласно правилам GoF, цель паттерна Observer:
Скопируйте код кода следующим образом:
Определите связь зависимости «один ко многим» между объектами. Если состояние объекта изменится, другие связанные объекты будут уведомлены и автоматически обновлены.
Субъекты содержат наблюдателей, которых необходимо уведомлять при изменении их состояния. Поэтому он должен предоставить наблюдателям методы регистрации и отмены регистрации. Когда субъект (наблюдаемый) меняется, он также должен включать метод уведомления всех наблюдателей. Уведомляя наблюдателей, вы можете отправлять обновления или предоставить другой метод получения обновлений.
У наблюдателей должен быть метод, который устанавливает объект-наблюдатель и может использоваться наблюдаемым для уведомления об обновлениях.
JAVA предоставляет встроенные способы реализации шаблона наблюдателя, интерфейсы java.util.Observable и java.util.Observer. Однако они не очень широко используются. Поскольку эта реализация слишком проста, в большинстве случаев мы не хотим, чтобы последний расширенный класс просто реализовал шаблон наблюдателя, поскольку классы JAVA не могут наследовать несколько раз.
Служба сообщений Java Messages Service (JMS) использует режим наблюдателя и командный режим для реализации публикации и подписки данных между различными программами.
Платформа управления представлением модели MVC также использует шаблон наблюдателя, рассматривая модель как наблюдаемое, а представление как наблюдателя. Представления могут регистрироваться в модели, чтобы получать изменения в модели.
Пример шаблона наблюдателя
В этом примере мы завершим простое обсуждение темы, и наблюдатели смогут зарегистрироваться на эту тему. Любые изменения, возникшие в результате отправки контента по этой теме, будут уведомлены всем зарегистрированным наблюдателям.
Исходя из потребностей наблюдателей субъекта, это реализация базового интерфейса субъекта. Этот интерфейс определяет ряд конкретных методов, которые необходимо реализовать в конкретном классе, который впоследствии реализует интерфейс.
Скопируйте код кода следующим образом:
пакет com.journaldev.design.observer;
публичный интерфейс Тема {
//методы регистрации и отмены регистрации наблюдателей
публичный недействительный реестр (Observer obj);
общественная недействительная отмена регистрации (Observer obj);
//метод уведомления наблюдателей об изменениях
общественная недействительность notifyObservers ();
//метод получения обновлений от субъекта
общедоступный объект getUpdate (observer obj);
}
Теперь создайте связанного наблюдателя. Ему нужен метод, позволяющий прикрепить Субъект к наблюдателю. Дополнительные методы могут принимать уведомления об изменении темы.
Скопируйте код кода следующим образом:
пакет com.journaldev.design.observer;
публичный интерфейс наблюдателя {
//метод обновления наблюдателя, используемый субъектом
общественное недействительное обновление();
//присоединяем к объекту наблюдения
общественная недействительность setSubject (Subject sub);
}
Эта связь установлена. Теперь реализуйте конкретную тему.
Скопируйте код кода следующим образом:
пакет com.journaldev.design.observer;
импортировать java.util.ArrayList;
импортировать java.util.List;
публичный класс MyTopic реализует Тему {
частные наблюдатели List<Observer>;
личное строковое сообщение;
изменено частное логическое значение;
частный конечный объект MUTEX = новый объект();
публичная моя тема() {
this.observers=new ArrayList<>();
}
@Override
публичный недействительный регистр (Observer obj) {
if(obj == null) throw new NullPointerException("Null Observer");
if(!observers.contains(obj)) Observers.add(obj);
}
@Override
public void unregister (observer obj) {
наблюдатели.удалить(объект);
}
@Override
общественный недействительный notifyObservers () {
List<Observer> наблюдателиLocal = null;
//синхронизация используется, чтобы гарантировать, что любой наблюдатель, зарегистрированный после получения сообщения, не будет уведомлен
синхронизированный (MUTEX) {
если (!изменилось)
возвращаться;
наблюдателиLocal = новый ArrayList<>(this.observers);
this.changed=false;
}
for (Observer obj: ObserversLocal) {
объект.обновление();
}
}
@Override
общедоступный объект getUpdate (observer obj) {
вернуть это сообщение;
}
//метод отправки сообщения в тему
общественный недействительный postMessage (String msg) {
System.out.println("Сообщение, опубликованное в теме:"+msg);
this.message=msg;
this.changed=истина;
уведомитьОбсерверс();
}
}
Реализация регистрации и отмены регистрации методов наблюдателя очень проста. Дополнительный метод postMessage() будет использоваться клиентом для отправки строкового сообщения в эту тему. Обратите внимание, что логические переменные используются для отслеживания изменений состояния темы и уведомления наблюдателей о таких изменениях. Эта переменная необходима, потому что если обновления нет, но кто-то вызывает метод notifyObservers(), он не может отправить наблюдателям информацию об уведомлении об ошибке.
Кроме того, следует отметить, что в notifyObservers() используется синхронизация, чтобы гарантировать, что уведомления могут быть отправлены только зарегистрированным наблюдателям до того, как сообщение будет опубликовано в теме.
Вот реализация наблюдателя. Они всегда будут сосредоточены на предметном объекте.
Скопируйте код кода следующим образом:
пакет com.journaldev.design.observer;
публичный класс MyTopicSubscriber реализует Observer {
частное имя строки;
частная тема;
public MyTopicSubscriber (String nm) {
this.name=нм;
}
@Override
общественное недействительное обновление () {
String msg = (String) theme.getUpdate(this);
если (сообщение == ноль) {
System.out.println(name+"::Нет нового сообщения");
}еще
System.out.println(name+":: Потребляющее сообщение::"+msg);
}
@Override
public void setSubject (Subject sub) {
this.topic=sub;
}
}
Обратите внимание, что реализация метода update() использует метод getUpdate() наблюдателя для обработки обновленных сообщений. Здесь следует избегать передачи сообщения в качестве параметра методу update().
Вот простая тестовая программа для проверки реализации тематического класса.
Скопируйте код кода следующим образом:
пакет com.journaldev.design.observer;
общественный класс ObserverPatternTest {
public static void main(String[] args) {
//создаем тему
Тема MyTopic = новая MyTopic();
//создаем наблюдателей
Наблюдатель obj1 = новый MyTopicSubscriber("Obj1");
Наблюдатель obj2 = новый MyTopicSubscriber("Obj2");
Наблюдатель obj3 = новый MyTopicSubscriber("Obj3");
//регистрируем наблюдателей к субъекту
тема.регистр(obj1);
тема.регистр(obj2);
тема.регистр(obj3);
//прикрепляем наблюдателя к субъекту
obj1.setSubject(тема);
obj2.setSubject(тема);
obj3.setSubject(тема);
//проверяем, доступно ли какое-либо обновление
объект1.обновление();
//теперь отправляем сообщение субъекту
theme.postMessage("Новое сообщение");
}
}
Вот приведенный выше вывод:
Скопируйте код кода следующим образом:
Obj1::Нет нового сообщения
Сообщение опубликовано в теме:Новое сообщение
Obj1::Consuming message::Новое сообщение
Obj2::Consuming message::Новое сообщение
Obj3::Consuming message::Новое сообщение</pre>
UML-диаграмма шаблона наблюдателя
Шаблон наблюдателя также называется шаблоном публикации-подписки. Вот некоторые конкретные приложения в JAVA:
1.java.util.EventListener в Swing
2.javax.servlet.http.HttpSessionBindingListener
3.javax.servlet.http.HttpSessionAttributeListener
Вышеупомянутые режимы — все режимы наблюдателя. Надеюсь, оно вам уже понравилось. Поделитесь своими чувствами в комментариях или поделитесь с другими.