Dokumentation

This commit is contained in:
ngb
2022-12-10 11:14:38 +01:00
parent e2e1f24e3e
commit 97ea610f34
2 changed files with 61 additions and 0 deletions

View File

@@ -7,6 +7,60 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
/**
* Implementierung einer EventListener-API basierend auf dem Artikel
* <a href="https://org.coloradomesa.edu/~wmacevoy/listen/paper.html">Skilled
* Listening in Java</a> von Dr. Warren D. MacEvoy.
* <p>
* Der {@code EventDispatcher} verwaltet eine Liste von angemeldeten Listenern
* in einem {@link CopyOnWriteArraySet}, dass besonders für Situationen geeignet
* ist, in denen in der Regel wenige Objekte verwaltet werden müssen, auf die
* schnell zugegriffen werden soll und die sich selten ändern. Das trifft in den
* meisten Fällen auf die Listener eines Objekts zu.
* <p>
* Um einen {@code EventDispatcher} zu nutzen, muss eine Schnittstelle als
* Unterinterface von {@link Listener} erstellt werden, die Methoden für die
* einzelnen Events definiert. In der Regel wird eine Methode pro Event
* angelegt, aber dies ist nicht unbedingt notwendig.
* <p>
* Ein Objekt, dass Events für diese Art von Listener erzeugt, erstellt einen
* {@code EventDispatcher} und
* {@link #registerEventType(String, BiConsumer) registriert} die notwendigen
* Events.
*
* <pre><code>
* EventDispatcher&lt;MyEvent, MyEventListener&gt; dispatcher = new EventDispatcher&lt;&gt;();
* dispatcher.registerEventType("start", (evt, listener) -> listener.started(evt));
* dispatcher.registerEventType("stop", (evt, listener) -> listener.stopped(evt));
* </code></pre>
* <p>
* Hier werden zwei Events registriert "start" und "stop". Die Bezeichnung der
* Events wird nut intern verwendet. Jedes Event registriert eine Funktion, die
* den Aufruf der Listener-Schnittstelle umsetzt. In der Regel ist dies ein
* Lambda-Ausdruck von zwei Parametern: dem Event-Objekt vom Typ {@code E} und
* der Listener, der aufgerufen werden soll, vom Typ {@code L}.
* <p>
* Nun können {@code MyEventListener} angemeldet und Events ausgelöst werden.
*
* <pre><code>
* public void addEventListener( MyEventListener listener ) {
* dispatcher.addListener(listener);
* }
*
* public void removeEventListener( MyEventListener listener ) {
* dispatcher.removeListener(listener);
* }
*
* public void methodThatCreatesEvents() {
* dispatcher.dispatchEvent("start", new MyEvent());
* // Do something
* dispatcher.dispatchEvent("stop", new MyEvent());
* }
* </code></pre>
*
* @param <E> Typ der Event-Objekte.
* @param <L> Typ der verwendeten Listener-Schnittstelle.
*/
public class EventDispatcher<E, L extends Listener<E>> { public class EventDispatcher<E, L extends Listener<E>> {
private final CopyOnWriteArraySet<L> listeners; private final CopyOnWriteArraySet<L> listeners;
@@ -35,6 +89,7 @@ public class EventDispatcher<E, L extends Listener<E>> {
listeners.remove(listener); listeners.remove(listener);
} }
@SuppressWarnings("unused")
public boolean hasListeners() { public boolean hasListeners() {
return !listeners.isEmpty(); return !listeners.isEmpty();
} }

View File

@@ -1,5 +1,11 @@
package schule.ngb.zm.util.events; package schule.ngb.zm.util.events;
/**
* Generische Basisschnittstelle für die Implementierung von EventListenern.
*
* @param <E> Typ der Event-Objekte, die von diesem Listener empfangen werden.
* @see EventDispatcher
*/
public interface Listener<E> { public interface Listener<E> {
} }