Einfaches Eventhandling führt zu Brett vor Kopf

temi

Top Contributor
Ich komm hier nicht mehr weiter, vielleicht geht das auch gar nicht, was ich möchte. Vielleicht hat ja einer von euch die richtige Lösung.

Ich versuche mir ein einfaches Eventhandling zu programmieren. FxEvent ist ein einfaches Markerinterface für einen Eventtyp
Java:
public class FxEvents implements FxEventBus {

    private final Map<Class<? extends FxEvent>, List<Consumer<FxEvent>>> listeners = new HashMap<>();

    @Override
    public void publish(FxEvent event) {
        Class<? extends FxEvent> eventClass = event.getClass();
        var eventListeners = listeners.get(eventClass);
        for(var listener : eventListeners) {
            listener.accept(event);
        }
    }

    @Override
    public <T extends FxEvent> void register(final Class<T> eventClass, final Consumer<FxEvent> listener) {
        if (!listeners.containsKey(eventClass)) {
            listeners.put(eventClass, new LinkedList<>());
        }

        listeners.get(eventClass).add(listener);
    }
}

// Ein Event-Dummy
public class BlubEvent implements FxEvent { }

// und eine Listener-Methode

public void handleBlub(BlubEvent blub) { }

// und die Registrierung, die leider fehlschlägt
eventBus.register(BlubEvent.class, this::handleBlub); // <== Incompatible types: FxEvent is not convertible to BlubEvent

Ein Versuch, dass Problem zu beheben:
Java:
public <T extends FxEvent> void register(final Class<T> eventClass, final Consumer<T> listener) { // <== Consumer<T> mit <T extends FxEvent>
    if (!listeners.containsKey(eventClass)) {
        listeners.put(eventClass, new LinkedList<>());
    }

    listeners.get(eventClass).add(listener); // <== listener kann nicht mehr hinzugefügt werden: required Type: FxEvent
}
Zusätzlich noch:
Java:
private final Map<Class<? extends FxEvent>, List<Consumer<? extends FxEvent>>> listeners = new HashMap<>(); // <== List<Consumer<? extends FxEvent>>>

// damit funktioniert das Hinzufügen, aber jetzt kommt der Fehler hier:
for(var listener : eventListeners) {
    listener.accept(event); // <== Required type: capture of ? extends FxEvent, Provided: FxEvent
}

Hat jemand einen Tipp für mich?
 
Im Zweifelsfall casten. Ich hab gerade nicht die Zeit & Nerven mich da intensiver mit zu beschäftigen, Generics mit extends sind manchmal etwas zickig.

Dein erster Versuch sieht auf jeden Fall gut aus. Wichtig ist, dass das Interface nach außen sauber ist und keinen Unfug erlaubt. Daher ist

Java:
public <T extends FxEvent> void register(final Class<T> eventClass, final Consumer<T> listener)
das besser als das:

Java:
    public <T extends FxEvent> void register(final Class<T> eventClass, final Consumer<FxEvent> listener)
Weil so erhält der Consumer direkt das Event vom richtigen Typ und muss nicht mehr selber casten.

Intern kannst du in deiner Klasse einfach auf die richtigen Typen casten. Generics existieren ja eh nur zur Laufzeit. Das heißt, du kannst den Listener einfach auf den erwarteten Typ casten.

Es gibt evtl. auch eine sauberere Lösung, aber da fehlt mir gerade die Zeit für.
 

Neue Themen


Zurück
Oben