Простая реализация шаблона наблюдателя
Скопируйте код кода следующим образом:
импортировать java.util.ArrayList;
импортировать java.util.Collections;
импортировать java.util.Iterator;
импортировать java.util.List;
/**
* Обратные вызовы используются в режиме наблюдателя:
* A. Наблюдатель регистрируется в списке слушателей наблюдаемого, а сам класс наблюдателя предоставляет функцию обратного вызова.
* B. Наблюдаемый (Наблюдаемый или Субъект) ведет список наблюдателей и может регистрировать и отменять регистрацию наблюдателей.
* C. Как только статус наблюдателя изменится, он может вызвать notifyObservers(). Этот метод будет проходить по списку наблюдателей и вызывать его один за другим.
функция обратного вызова, предоставляемая наблюдателем
* @author будет
*
*/
общественный класс SimpleObserverPattern {
public static void main(String[] args) {
SimpleObserverPattern sop = новый SimpleObserverPattern();
Наблюдатели List<IObserver> = новый ArrayList<IObserver> ();
IObserver ObserverA = sop.new Observer("ObserverA");
IObserver ObserverB = sop.new Observer("ObserverB");
наблюдатели.add(observerA);
наблюдатели.add(observerB);
IObservable наблюдаемый = sop.new Observable(наблюдатели);
observable.registerObserver(sop.new Observer("ObserverC"));
наблюдаемый.changeState();
наблюдаемый.закрыть();
}
// Человек, за которым наблюдают, в некоторых местах называется Субъектом.
интерфейс IObservable {
void RegisterObserver (наблюдатель IObserver);
void unregisterObserver (наблюдатель IObserver);
недействительными notifyObservers();
Строка getState();
недействительный ChangeState();
недействительно закрыть();
}
класс Observable реализует IObservable {
Private static Final String NEW = "Новый";
частная статическая окончательная строка CHANGED = «Изменено»;
частная статическая окончательная строка CLOSED = «Закрыто»;
состояние частной строки;
частные наблюдатели List<IObserver>;
общественный наблюдаемый () {
это (ноль);
}
public Observable(List<IObserver> наблюдатели) {
если (наблюдатели == ноль) {
наблюдатели = новый ArrayList<IObserver> ();
}
this.observers = Collections.synchronizedList(наблюдатели);
this.state = НОВЫЙ;
}
@Override
public void RegisterObserver (наблюдатель IObserver) {
наблюдатели.добавить(наблюдатель);
}
@Override
public void unregisterObserver (наблюдатель IObserver) {
наблюдатели.удалить(наблюдатель);
}
@Override
общественный недействительный notifyObservers () {
Iterator<IObserver> iter = Observers.iterator();
while(iter.hasNext()) {
iter.next().update(это);
}
}
@Override
публичная строка getState() {
возвратное состояние;
}
@Override
общественный недействительный ChangeState () {
this.state = ИЗМЕНЕНО;
уведомитьОбсерверов();
}
@Override
общественная недействительность close () {
this.state = ЗАКРЫТО;
уведомитьОбсерверов();
}
}
интерфейс IObserver {
недействительное обновление (IObservable observalbe);
}
класс Observer реализует IObserver {
частное имя строки;
общественный наблюдатель (имя строки) {
это.имя = имя;
}
@Override
public void update(IObservable observalbe) {
System.out.println(
String.format("%s получает изменение наблюдения, текущее состояние наблюдения — %s",
имя, observalbe.getState()));
}
}
}
Приведенная выше реализация напрямую использует наблюдаемый объект в качестве параметра функции обратного вызова. Это очень неэлегантно и может работать в простых сценариях.
Но на самом деле в большинстве случаев у наблюдаемого человека есть много событий или состояний, и каждый наблюдатель может быть заинтересован в разных событиях или состояниях, или в целях сокрытия информации мы не хотим, чтобы каждый наблюдатель мог иметь доступ ко всем состояниям. внутри Observable.
Таким образом, я продолжил развивать код до следующей версии. Обратите внимание, что здесь я не рассматривал подробно вопросы параллелизма.
Скопируйте код кода следующим образом:
импортировать java.util.Collections;
импортировать java.util.HashSet;
импортировать java.util.Hashtable;
импортировать java.util.Iterator;
импортировать java.util.Set;
общественный класс MultiEventObserverPattern {
public static void main(String[] args) {
MultiEventObserverPattern meop = новый MultiEventObserverPattern();
IObservable observable = meop.new Observable();
IObserver ObserverA = meop.new Observer("ObserverA");
IObserver ObserverB = meop.new Observer("ObserverB");
//Регистрируем интересующие события
observable.registerObserver(observable.getEventA(), ObserverA);
observable.registerObserver(observable.getEventB(), ObserverB);
//Изменяем наблюдаемое состояние
наблюдаемый.changeStateA();
наблюдаемый.changeStateB();
}
интерфейс IEvent {
недействительный eventChange();
Строка getState();
}
класс EventA реализует IEvent {
частная статическая окончательная строка INITIALIZED = «Инициализировано»;
частная статическая окончательная строка PENDING = "Ожидание";
состояние частной строки;
общественное событиеA() {
this.state = ИНИЦИАЛИЗИРОВАНО;
}
@Override
общественный недействительный eventChange () {
System.out.println("Изменение EventA");
this.state = ОЖИДАНИЕ;
}
@Override
публичная строка toString() {
вернуть «СобытиеА»;
}
@Override
публичная строка getState() {
возвратное состояние;
}
}
класс EventB реализует IEvent {
Private static Final String NEW = "Новый";
частная статическая окончательная строка IDLE = "Idle";
состояние частной строки;
общественное событиеB() {
this.state = НОВЫЙ;
}
@Override
общественный недействительный eventChange () {
System.out.println("Изменение EventB");
this.state = IDLE;
}
@Override
публичная строка toString() {
вернуть «Событие Б»;
}
@Override
публичная строка getState() {
возвратное состояние;
}
}
// Наблюдаемый, иногда называемый Субъектом
интерфейс IObservable {
void RegisterObserver (событие IEvent, наблюдатель IObserver);
void unregisterObserver (событие IEvent, наблюдатель IObserver);
//Уведомляем наблюдателей о том, что произошло событие
void notifyObservers (событие IEvent);
недействительным ChangeStateA ();
недействительный ChangeStateB ();
IEvent getEventA();
IEvent getEventB();
}
класс Observable реализует IObservable {
частное событие IEventA;
частное событие IEventB;
частная Hashtable<IEvent, Set<IObserver>> eventObserverMapping;
общественный наблюдаемый () {
это (ноль);
}
// Если некоторые из Set<IObserver>, переданные EvenObserverMapping, не были изменены синхронно, вы ничего не можете с этим поделать.
public Observable(Hashtable<IEvent, Set<IObserver>> eventObserverMapping) {
если (eventObserverMapping == null) {
eventObserverMapping = новая Hashtable<IEvent, Set<IObserver>> ();
}
this.eventObserverMapping = новая Hashtable<IEvent, Set<IObserver>> ();
this.eventA = новое EventA();
this.eventB = новое EventB();
}
@Override
public void RegisterObserver (событие IEvent, наблюдатель IObserver) {
Set<IObserver> наблюдатели = eventObserverMapping.get(event);
если (наблюдатели == ноль) {
наблюдатели = Collections.synchronizedSet(new HashSet<IObserver> ());
наблюдатели.добавить(наблюдатель);
eventObserverMapping.put(событие, наблюдатели);
}
еще {
наблюдатели.добавить(наблюдатель);
}
}
@Override
public void unregisterObserver (событие IEvent, наблюдатель IObserver) {
Set<IObserver> наблюдатели = eventObserverMapping.get(event);
если (наблюдатели! = ноль) {
наблюдатели.удалить(наблюдатель);
}
}
@Override
public void notifyObservers (событие IEvent) {
Set<IObserver> наблюдатели = eventObserverMapping.get(event);
if(observers != null && Observers.size() > 0) {
Iterator<IObserver> iter = Observers.iterator();
while(iter.hasNext()) {
iter.next().update(событие);
}
}
}
@Override
общественная недействительность ChangeStateA () {
// Изменение состояния A вызовет событие A
событиеA.eventChange();
notifyObservers (событиеA);
}
@Override
общественная недействительность ChangeStateB () {
// Изменение состояния B вызовет событие B
событиеB.eventChange();
notifyObservers (событиеB);
}
@Override
общественный IEvent getEventA() {
вернуть событие А;
}
@Override
общественный IEvent getEventB () {
вернуть событие Б;
}
}
интерфейс IObserver {
недействительное обновление (событие IEvent);
}
класс Observer реализует IObserver {
частное имя строки;
общественный наблюдатель (имя строки) {
это.имя = имя;
}
@Override
общественное недействительное обновление (событие IEvent) {
System.out.println(
String.format("%s получает изменение %s, текущее состояние наблюдения — %s",
имя, событие, event.getState()));
}
}
}
Вроде бы все идеально, но все же не идеально. Потому что события жестко запрограммированы как свойства класса Observer. Таким образом, тип события определяется во время компиляции. Если вы хотите добавить новый тип события, вам придется изменить интерфейс IObservable и класс Observable, что значительно снижает гибкость.
Это эквивалентно тому, что наблюдатель связан с этими конкретными событиями, так как же нам преодолеть это ограничение?
Ответ заключается в том, чтобы ввести новый компонент и позволить этому компоненту управлять отношениями между событиями, наблюдателями и наблюдаемыми объектами. Когда происходит событие, этот компонент также вызывает функцию обратного вызова наблюдателя. Это также своего рода развязка, чем-то похожая на IOC-контейнер Spring.
Что касается конкретной реализации, я думаю, что Guava EventBus проделал довольно хорошую работу. Вы можете обратиться к ссылке, которую я упоминал ранее.
PS: Этот пост не является рекламой Guava EventBus, но мои собственные идеи продвигаются шаг за шагом, и постепенно они согласуются с дизайнерскими идеями Guava EventBus.
Давайте продолжим рассматривать пример стандартного класса JDK, реализующего шаблон наблюдателя, а затем проанализируем его реализацию в исходном коде. Все, что нам нужно, — это класс Observable и интерфейс Observer.
Стандартные классы JDK реализуют шаблон наблюдателя
Скопируйте код кода следующим образом:
импортировать java.util.Observable;
импортировать java.util.Observer;
/**
* Реализуйте шаблон наблюдателя, используя стандартные классы в пакете java.util.
* @author будет
*
*/
общественный класс JDKObserverDemo {
public static void main(String[] args) {
JDKObserverDemo jod = новый JDKObserverDemo();
// Наблюдатель
MyObservable myObservable = jod.new MyObservable("привет");
// Наблюдатель
Наблюдатель myObserver = jod.new MyObserver();
// регистрация
myObservable.addObserver(мойObserver);
//Изменяем наблюдаемое состояние и запускаем функцию обратного вызова наблюдателя
myObservable.setValue("будет");
}
класс MyObservable расширяет Observable {
частная строка watchValue // наблюдаемое значение;
public MyObservable (String WatchValue) {
this.watchedValue = WatchedValue;
}
public void setValue (String newValue) {
if(!watchedValue.equals(newValue)) {
наблюдалиЗначение = новоеЗначение;
УстановитьИзменено();
notifyObservers (новое значение);
}
}
@Override
публичная строка toString() {
вернуть «MyObservable»;
}
}
класс MyObserver реализует Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println(o + "состояние изменено, аргумент: " + arg);
}
}
}
Посмотрев на реализацию Observer и Observable в стандартной библиотеке JDK, она очень проста, поэтому больше говорить не хочу.
Ниже представлена реализация слушателя в Quartz.
Слушатель QuartzScheduler
Скопируйте код кода следующим образом:
импортировать java.util.ArrayList;
импортировать java.util.Date;
импортировать java.util.List;
/**
*Класс ядра Quartz, эквивалентный Observable (наблюдаемый)
* @author будет
*
*/
общественный класс QuartzScheduler {
частный ArrayList<SchedulerListener> InternalSchedulerListeners = новый ArrayList<SchedulerListener>(10);
//private ArrayList<JobListener> interanlJobListeners = new ArrayList<JobListener>(); // Observable может содержать несколько наборов прослушивателей
public Date ScheduleJob (Триггерный триггер) {
если (триггер == ноль) {
вернуть ноль;
}
System.out.println("Запланировать задание, триггер: " + триггер);
notifySchedulerListenersScheduled (триггер);
вернуть новую дату();
}
public void unScheduleJob (триггер-триггер) {
если (триггер == ноль) {
возвращаться;
}
System.out.println("Отменить планирование задания, триггер: " + триггер);
notifyShedulerListenerUnScheduled (триггер);
}
//Регистрация прослушивателя планировщика
public void addInternalSchedulerListener (SchedulerListener SchedulerListener) {
синхронизированный (internalSchedulerListeners) {
InternalSchedulerListeners.add(schedulerListener);
}
}
// Удаление прослушивателя планировщика
public boolean removeInternalSchedulerListener(SchedulerListener SchedulerListener) {
синхронизированный (internalSchedulerListeners) {
return InternalSchedulerListeners.remove(schedulerListener);
}
}
public List<SchedulerListener> getInternalSchedulerListeners() {
синхронизированный (internalSchedulerListeners) {
return java.util.Collections.unmodifyingList(new ArrayList<SchedulerListener>(internalSchedulerListeners));
}
}
public void notifySchedulerListenersScheduled (триггер триггера) {
for(SchedulerListener прослушиватель: getInternalSchedulerListeners()) {
прослушиватель.jobScheduled(триггер);
}
}
public void notifyShedulerListenerUnScheduled (триггер триггера) {
for(SchedulerListener прослушиватель: getInternalSchedulerListeners()) {
прослушиватель.jobUnScheduled(триггер);
}
}
}
ПланировщикПрослушиватель
Скопируйте код кода следующим образом:
// Интерфейс прослушивания, функция обратного вызова. Клиенту необходимо предоставить реализацию функции обратного вызова при регистрации для мониторинга.
общедоступный интерфейс SchedulerListener {
void jobScheduled (триггер-триггер);
void jobUnScheduled (триггер-триггер);
}
Курок
Скопируйте код кода следующим образом:
//Курок
публичный класс Trigger {
частная строка триггерного ключа;
частная строка TriggerName;
public Trigger (String TriggerKey, String TriggerName) {
this.triggerKey = триггерKey;
this.triggerName = имя триггера;
}
публичная строка getTriggerKey() {
вернуть триггерный ключ;
}
public void setTriggerKey (String TriggerKey) {
this.triggerKey = триггерKey;
}
публичная строка getTriggerName() {
вернуть имя триггера;
}
public void setTriggerName (String TriggerName) {
this.triggerName = имя триггера;
}
публичная строка toString() {
return String.format("{triggerKey: %s, TriggerName: %s}", TriggerKey, TriggerName);
}
}
Тест
Скопируйте код кода следующим образом:
тест публичного класса {
public static void main(String[] args) {
QuartzScheduler qs = новый QuartzScheduler();
SchedulerListener ListenerA = новый SchedulerListener() {
@Override
public void jobUnScheduled (триггер-триггер) {
System.out.println("Задание прослушивателяA незапланировано: " + триггер.getTriggerName());
}
@Override
public void jobScheduled (триггер-триггер) {
System.out.println("Задание прослушивателяA запланировано: " + триггер.getTriggerName());
}
};
SchedulerListener ListenerB = новый SchedulerListener() {
@Override
public void jobUnScheduled (триггер-триггер) {
System.out.println("Задание прослушивателяB незапланировано: " + триггер.getTriggerName());
}
@Override
public void jobScheduled (триггер-триггер) {
System.out.println("Запланировано задание прослушивателяB: " + триггер.getTriggerName());
}
};
//Регистрация прослушивателя планировщика
qs.addInternalSchedulerListener(listenerA);
qs.addInternalSchedulerListener(listenerB);
Триггер триггерА = новый триггер("Ключ1", "триггерА");
Триггер триггерB = новый триггер("Ключ2", "триггерB");
qs.scheduleJob(triggerA);
qs.scheduleJob(triggerB);
qs.unScheduleJob(triggerA);
}
}