Einfache Implementierung des Beobachtermusters
Kopieren Sie den Codecode wie folgt:
import java.util.ArrayList;
java.util.Collections importieren;
import java.util.Iterator;
java.util.List importieren;
/**
* Rückrufe werden im Beobachtermodus verwendet:
* A. Der Beobachter registriert sich in der Listener-Liste der Beobachteten und die Beobachterklasse selbst stellt eine Rückruffunktion bereit
* B. Das Beobachtbare (Beobachtbare oder Subjekt) führt eine Liste von Beobachtern und kann Beobachter registrieren und abmelden
* C. Sobald sich der Status des Beobachters ändert, kann er notifyObservers() aufrufen. Diese Methode durchläuft die Beobachterliste und ruft sie einzeln auf.
Rückruffunktion, die vom Beobachter bereitgestellt wird
* @author wird
*
*/
öffentliche Klasse SimpleObserverPattern {
public static void main(String[] args) {
SimpleObserverPattern sop = new SimpleObserverPattern();
List<IObserver> Observers = new ArrayList<IObserver> ();
IObserver ObserverA = sop.new Observer("ObserverA");
IObserver ObserverB = sop.new Observer("ObserverB");
Observers.add(observerA);
Observer.add(observerB);
IObservable observable = sop.new Observable(observers);
observable.registerObserver(sop.new Observer("ObserverC"));
observable.changeState();
observable.close();
}
// Die beobachtete Person wird an manchen Stellen Subjekt genannt.
Schnittstelle IObservable {
void registerObserver(IObserver Observer);
void unregisterObserver(IObserver Observer);
void notifyObservers();
String getState();
void changeState();
void close();
}
Klasse Observable implementiert IObservable {
private static final String NEW = „New“;
private static final String CHANGED = „Changed“;
private static final String CLOSED = „Closed“;
privater String-Status;
private List<IObserver>-Beobachter;
public Observable() {
this(null);
}
public Observable(List<IObserver> Observer) {
if(observers == null) {
Observer = new ArrayList<IObserver> ();
}
this.observers = Collections.synchronizedList(observers);
this.state = NEU;
}
@Override
public void registerObserver(IObserver Observer) {
observers.add(observer);
}
@Override
public void unregisterObserver(IObserver Observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
Iterator<IObserver> iter = Observers.iterator();
while(iter.hasNext()) {
iter.next().update(this);
}
}
@Override
öffentlicher String getState() {
Rückkehrzustand;
}
@Override
public void changeState() {
this.state = GEÄNDERT;
notifyObservers();
}
@Override
public void close() {
this.state = GESCHLOSSEN;
notifyObservers();
}
}
Schnittstelle IObserver {
void update(IObservable observalbe);
}
Klasse Observer implementiert IObserver {
privater String-Name;
public Observer(String name) {
this.name = Name;
}
@Override
öffentliches Void-Update(IObservable observalbe) {
System.out.println(
String.format("%s erhält die Änderung von Observalbe, der aktuelle Status von Observalbe ist %s",
name, observalbe.getState()));
}
}
}
Die obige Implementierung verwendet das beobachtete Objekt direkt als Callback-Funktionsparameter. Dies ist sehr unelegant und kann in einfachen Szenarien funktionieren.
Tatsächlich hat eine beobachtete Person jedoch in mehr Fällen viele Ereignisse oder Zustände, und jeder Beobachter ist möglicherweise an verschiedenen Ereignissen oder Zuständen interessiert, oder zum Zwecke der Informationsverbergung möchten wir nicht, dass jeder Beobachter auf alle Zustände zugreifen kann innerhalb des Observablen.
Auf diese Weise habe ich den Code zur folgenden Version weiterentwickelt. Beachten Sie, dass ich hier nicht im Detail auf Parallelitätsprobleme eingegangen bin.
Kopieren Sie den Codecode wie folgt:
java.util.Collections importieren;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
öffentliche Klasse MultiEventObserverPattern {
public static void main(String[] args) {
MultiEventObserverPattern meop = new MultiEventObserverPattern();
IObservable observable = meop.new Observable();
IObserver ObserverA = meop.new Observer("ObserverA");
IObserver ObserverB = meop.new Observer("ObserverB");
//Interessante Ereignisse registrieren
observable.registerObserver(observable.getEventA(), ObserverA);
observable.registerObserver(observable.getEventB(), ObserverB);
//Den beobachteten Zustand ändern
observable.changeStateA();
observable.changeStateB();
}
Schnittstelle IEvent {
void eventChange();
String getState();
}
Klasse EventA implementiert IEvent {
private static final String INITIALIZED = "Initialized";
private static final String PENDING = "Pending";
privater String-Status;
öffentliches EventA() {
this.state = INITIALIZED;
}
@Override
public void eventChange() {
System.out.println("EventA change");
this.state = PENDING;
}
@Override
öffentlicher String toString() {
return „EventA“;
}
@Override
öffentlicher String getState() {
Rückkehrzustand;
}
}
Klasse EventB implementiert IEvent {
private static final String NEW = „New“;
private static final String IDLE = „Idle“;
privater String-Status;
öffentliches EventB() {
this.state = NEU;
}
@Override
public void eventChange() {
System.out.println("EventB-Änderung");
this.state = IDLE;
}
@Override
öffentlicher String toString() {
return „EventB“;
}
@Override
öffentlicher String getState() {
Rückkehrzustand;
}
}
// Beobachtbar, manchmal auch Subjekt genannt
Schnittstelle IObservable {
void registerObserver(IEvent-Ereignis, IObserver-Beobachter);
void unregisterObserver(IEvent event, IObserver Observer);
// Beobachter benachrichtigen, dass ein Ereignis aufgetreten ist
void notifyObservers(IEvent event);
void changeStateA();
void changeStateB();
IEvent getEventA();
IEvent getEventB();
}
Klasse Observable implementiert IObservable {
privates IEvent eventA;
privates IEvent eventB;
private Hashtable<IEvent, Set<IObserver>> eventObserverMapping;
public Observable() {
this(null);
}
// Wenn einige der von evenObserverMapping übergebenen Set<IObserver> nicht synchron geändert wurden, können Sie nichts dagegen tun.
public Observable(Hashtable<IEvent, Set<IObserver>> eventObserverMapping) {
if(eventObserverMapping == null) {
eventObserverMapping = new Hashtable<IEvent, Set<IObserver>> ();
}
this.eventObserverMapping = new Hashtable<IEvent, Set<IObserver>> ();
this.eventA = new EventA();
this.eventB = new EventB();
}
@Override
public void registerObserver(IEvent event, IObserver Observer) {
Set<IObserver> Observers = eventObserverMapping.get(event);
if(observers == null) {
Observer = Collections.synchronizedSet(new HashSet<IObserver> ());
observers.add(observer);
eventObserverMapping.put(event, Observer);
}
anders {
observers.add(observer);
}
}
@Override
public void unregisterObserver(IEvent event, IObserver Observer) {
Set<IObserver> Observers = eventObserverMapping.get(event);
if(Beobachter != null) {
observers.remove(observer);
}
}
@Override
public void notifyObservers(IEvent event) {
Set<IObserver> Observers = eventObserverMapping.get(event);
if(observers != null && Observers.size() > 0) {
Iterator<IObserver> iter = Observers.iterator();
while(iter.hasNext()) {
iter.next().update(event);
}
}
}
@Override
public void changeStateA() {
// Wenn sich Zustand A ändert, wird Ereignis A ausgelöst
eventA.eventChange();
notifyObservers(eventA);
}
@Override
public void changeStateB() {
// Eine Änderung des Zustands B löst Ereignis B aus
eventB.eventChange();
notifyObservers(eventB);
}
@Override
öffentliches IEvent getEventA() {
return eventA;
}
@Override
öffentliches IEvent getEventB() {
return eventB;
}
}
Schnittstelle IObserver {
void update(IEvent event);
}
Klasse Observer implementiert IObserver {
privater String-Name;
public Observer(String name) {
this.name = Name;
}
@Override
öffentliches Void-Update (IEvent-Ereignis) {
System.out.println(
String.format("%s erhält die Änderung von %s, der aktuelle Observalbe-Status ist %s",
Name, Ereignis, event.getState()));
}
}
}
Es scheint perfekt zu sein, aber es ist immer noch nicht perfekt. Weil Ereignisse als Eigenschaften der Observer-Klasse fest codiert sind. Auf diese Weise wird der Ereignistyp zur Kompilierzeit bestimmt. Wenn Sie einen neuen Ereignistyp hinzufügen möchten, müssen Sie die IObservable-Schnittstelle und die Observable-Klasse ändern, was die Flexibilität erheblich einschränkt.
Es ist gleichbedeutend damit, dass der Beobachter an diese spezifischen Ereignisse gekoppelt ist. Wie können wir diese Einschränkung durchbrechen?
Die Antwort besteht darin, eine neue Komponente einzuführen und diese Komponente die Beziehung zwischen Ereignissen, Beobachtern und beobachteten Objekten verwalten zu lassen. Wenn ein Ereignis auftritt, ruft diese Komponente auch die Rückruffunktion des Beobachters auf. Dies ist auch eine Art Entkopplung, ähnlich dem IOC-Container von Spring.
Was die konkrete Implementierung angeht, denke ich, dass Guava EventBus ziemlich gute Arbeit geleistet hat. Sie können auf den Link verweisen, den ich zuvor erwähnt habe.
PS: Dieser Beitrag ist keine Werbung für Guava EventBus, aber meine eigenen Ideen werden Schritt für Schritt weiterentwickelt und stimmen nach und nach mit den Designideen von Guava EventBus überein.
Schauen wir uns weiterhin das Beispiel der JDK-Standardklasse an, die das Beobachtermuster implementiert, und analysieren wir dann die Implementierung des Quellcodes. Alles, was wir uns ansehen müssen, ist eine Observable-Klasse und eine Observer-Schnittstelle.
JDK-Standardklassen implementieren Beobachtermuster
Kopieren Sie den Codecode wie folgt:
import java.util.Observable;
import java.util.Observer;
/**
* Implementieren Sie das Beobachtermuster mithilfe von Standardklassen im Paket java.util
* @author wird
*
*/
öffentliche Klasse JDKObserverDemo {
public static void main(String[] args) {
JDKObserverDemo jod = new JDKObserverDemo();
// Beobachter
MyObservable myObservable = jod.new MyObservable("hello");
// Beobachter
Beobachter myObserver = jod.new MyObserver();
// registrieren
myObservable.addObserver(myObserver);
//Ändern Sie den beobachteten Zustand und lösen Sie die Beobachter-Rückruffunktion aus
myObservable.setValue("will");
}
Klasse MyObservable erweitert Observable {
private String watchedValue; // der beobachtete Wert
public MyObservable(String watchedValue) {
this.watchedValue = watchedValue;
}
public void setValue(String newValue) {
if(!watchedValue.equals(newValue)) {
watchedValue = newValue;
setChanged();
notifyObservers(newValue);
}
}
@Override
öffentlicher String toString() {
return „MyObservable“;
}
}
Klasse MyObserver implementiert Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println(o + "'s Status geändert, Argument ist: " + arg);
}
}
}
Nachdem ich mir die Implementierung von Observer und Observable in der JDK-Standardbibliothek angesehen habe, ist sie sehr einfach, daher möchte ich nicht mehr sagen.
Unten finden Sie die Listener-Implementierung in Quartz.
QuartzScheduler-Listener
Kopieren Sie den Codecode wie folgt:
import java.util.ArrayList;
import java.util.Date;
java.util.List importieren;
/**
* Quarzkernklasse, äquivalent zu Observable (observable)
* @author wird
*
*/
öffentliche Klasse QuartzScheduler {
private ArrayList<SchedulerListener> internalSchedulerListeners = new ArrayList<SchedulerListener>(10);
//private ArrayList<JobListener> interanlJobListeners = new ArrayList<JobListener>(); // Ein Observable kann mehrere Sätze von Listenern enthalten
öffentlicher TerminplanJob(Trigger-Trigger) {
if(trigger == null) {
null zurückgeben;
}
System.out.println("Auftrag planen, Auslöser: " + Auslöser);
notifySchedulerListenersScheduled(trigger);
return new Date();
}
public void unScheduleJob(Trigger-Trigger) {
if(trigger == null) {
zurückkehren;
}
System.out.println("Job ausplanen, Auslöser: " + Auslöser);
notifyShedulerListenerUnScheduled(trigger);
}
//SchedulerListener registrieren
public void addInternalSchedulerListener(SchedulerListener SchedulerListener) {
synchronisiert (internalSchedulerListeners) {
internalSchedulerListeners.add(schedulerListener);
}
}
// SchedulerListener entfernen
öffentlicher boolescher Wert RemoveInternalSchedulerListener(SchedulerListener SchedulerListener) {
synchronisiert (internalSchedulerListeners) {
return internalSchedulerListeners.remove(schedulerListener);
}
}
public List<SchedulerListener> getInternalSchedulerListeners() {
synchronisiert (internalSchedulerListeners) {
return java.util.Collections.unmodifiableList(new ArrayList<SchedulerListener>(internalSchedulerListeners));
}
}
public void notifySchedulerListenersScheduled(Trigger-Trigger) {
for(SchedulerListener Listener: getInternalSchedulerListeners()) {
listener.jobScheduled(trigger);
}
}
public void notifyShedulerListenerUnScheduled(Trigger-Trigger) {
for(SchedulerListener Listener: getInternalSchedulerListeners()) {
listener.jobUnScheduled(trigger);
}
}
}
SchedulerListener
Kopieren Sie den Codecode wie folgt:
// Abhörschnittstelle, Rückruffunktion. Der Client muss bei der Registrierung für die Überwachung eine Implementierung der Rückruffunktion bereitstellen
öffentliche Schnittstelle SchedulerListener {
void jobScheduled(Trigger-Trigger);
void jobUnScheduled(Trigger-Trigger);
}
Auslösen
Kopieren Sie den Codecode wie folgt:
//Auslösen
öffentliche Klasse Trigger {
privater String triggerKey;
privater String triggerName;
public Trigger(String triggerKey, String triggerName) {
this.triggerKey = triggerKey;
this.triggerName = TriggerName;
}
öffentlicher String getTriggerKey() {
return triggerKey;
}
public void setTriggerKey(String triggerKey) {
this.triggerKey = triggerKey;
}
öffentlicher String getTriggerName() {
return triggerName;
}
public void setTriggerName(String triggerName) {
this.triggerName = TriggerName;
}
öffentlicher String toString() {
return String.format("{triggerKey: %s, triggerName: %s}", triggerKey, triggerName);
}
}
Prüfen
Kopieren Sie den Codecode wie folgt:
öffentlicher Klassentest {
public static void main(String[] args) {
QuartzScheduler qs = new QuartzScheduler();
SchedulerListener listenerA = new SchedulerListener() {
@Override
public void jobUnScheduled(Trigger-Trigger) {
System.out.println("listenerA job unplaned: " + trigger.getTriggerName());
}
@Override
public void jobScheduled(Trigger-Trigger) {
System.out.println("listenerA Job geplant: " + trigger.getTriggerName());
}
};
SchedulerListener listenerB = new SchedulerListener() {
@Override
public void jobUnScheduled(Trigger-Trigger) {
System.out.println("listenerB job unplaned: " + trigger.getTriggerName());
}
@Override
public void jobScheduled(Trigger-Trigger) {
System.out.println("listenerB-Job geplant: " + trigger.getTriggerName());
}
};
//Scheduler-Listener registrieren
qs.addInternalSchedulerListener(listenerA);
qs.addInternalSchedulerListener(listenerB);
Trigger triggerA = new Trigger("Key1", "triggerA");
Trigger triggerB = new Trigger("Key2", "triggerB");
qs.scheduleJob(triggerA);
qs.scheduleJob(triggerB);
qs.unScheduleJob(triggerA);
}
}