16 Stimmen

Polymorphes Dispatching in Java

Im Folgenden möchte ich, dass EventHandler EventA auf eine Weise, EventB auf eine andere Weise und alle anderen Ereignisse (EventC, EventD) auf eine andere Weise behandelt. EventReceiver empfängt nur eine Referenz auf ein Ereignis und ruft EventHandler.handle() auf. Die Version, die immer aufgerufen wird, ist natürlich EventHandler.handle(Event event).

Ohne instanceOf zu verwenden, gibt es eine Möglichkeit, polymorph zu versenden (vielleicht über eine andere Methode in EventHandler oder Generika) an die entsprechende Handle-Methode?

class EventA extends Event {
}

class EventB extends Event {
}

class EventC extends Event {
}

class EventD extends Event {
}

class EventHandler {
    void handle(EventA event) {
       System.out.println("Handling EventA");
    }

    void handle(EventB event) {
       System.out.println("Handling EventB");
    }

    void handle(Event event) {
       System.out.println("Handling Event");
    }
}

class EventReceiver {
    private EventHandler handler;

    void receive(Event event) {
        handler.handle(event);
    }
}

14voto

Péter Török Punkte 111735

Das klingt nach einem Fall für die Anwendung (einer Variante) der Besuchermuster . (In gängigen OO-Sprachen wie C++, C# und Java sind Methoden einzelner Versand d.h. sie können jeweils nur für einen Typ polymorph sein. Mit Visitor kann man implementieren Doppelversand .)

Dies setzt jedoch voraus, dass Sie in der Lage sind, die Event Klassen, und schafft eine Abhängigkeit von Event s zu (einer Basisschnittstelle von) EventHandler .

class EventA extends Event {
  public handleBy(EventHandler eh) {
    eh.handleEventA(this);
  }
}

class EventB extends Event {
  public handleBy(EventHandler eh) {
    eh.handleEventB(this);
  }
}

class EventHandler {
    void handleEventA(EventA event) {
       System.out.println("Handling EventA");
    }

    void handleEventB(EventB event) {
       System.out.println("Handling EventB");
    }

    void handle(Event event) {
       event.handleBy(this);
    }
}

2voto

Riduidel Punkte 21566

Dies ist ein Anwendungsfall für Doppeldisposition nein (die, wie man ja wissen kann, entweder Visitor genannt wird) ? Ich werde Ihr Beispiel nur für EventA implementieren

class Event {
    /**
     * Will do some type escalation
     */
    void handleWith(EventHandler care) {
        care.handle(this);
    }
}

class EventA extends Event {
    /**
     * As event is EventA, this implementation is called, with its correct type forced by the cast
     */
    void handleWith(EventHandler care) {
        care.handle((EventA) this);
    }
}

class EventHandler {
    /**
     * Finally comes here
     */
    void handle(EventA event) {
       System.out.println("Handling EventA");
    }

    void handle(EventB event) {
       System.out.println("Handling EventB");
    }

    void handle(Event event) {
       System.out.println("Handling Event");
    }

    /**
     * Go here first and dispatch call to Event class
     */
    void doHandle(Event event) {
        event.handleWith(this);
    }
}

class EventReceiver {
    private EventHandler handler;

    void receive(Event event) {
        handler.doHandle(event);
    }
}

2voto

Michael Borgwardt Punkte 334642

In Java gibt es polymorphes Dispatch nur für das Objekt, auf dem eine Methode aufgerufen wird. Das bedeutet, dass die einzige Möglichkeit, echten Polymorphismus zu erhalten, darin besteht, die handle() Methode in die Event Schnittstelle selbst. Ich würde sogar sagen, dass dies die insgesamt bessere und OO-gerechtere Lösung ist, da ein "Handler", der mit Datenobjekten arbeitet, eher prozedural ist.

Jede andere Lösung (wie eine Map von Handler-Objekten, die auf die Klasse verschlüsselt sind) wird komplexer und weniger flexibel sein, insbesondere in Bezug auf Vererbung.

0voto

Sean Patrick Floyd Punkte 283617

Sie können eine Map verwenden und Ereignistypen zu Ereignisbehandlern zuordnen.

Map<Class<? extends Event>, Handler> map =
    new HashMap<Class<? extends Event>, Handler>();

void receive(Event event) {
    Handler handler = map.get(event.getClass());
    handler.handle(event);
}

0voto

Justin Dennahower Punkte 176

Ich weiß, wie man das mit einer gewissen Vorverarbeitung machen kann. Verwenden Sie etwas wie dieses:

public abstract class EventHandler<T extends Event> {
   public abstract void handle(T event, Class<T> c);
   public abstract Class<T> handles();
}

public class EventHandlerA extends EventHandler<EventA> {
   @Override
   public void handle(EventA event, Class<EventA> c) {
      System.out.println(event);
   }

   @Override
   public Class<EventA> handles() {
      return EventA.class;
   }    
}

Verwenden Sie dann eine Karte, um Ihre Handler zu organisieren

HashMap<Class<?>,Collection<EventHandler<?>> handlers;

Wenn ein Ereignis behandelt werden muss, rufen Sie einfach die Handler aus der Karte ab. Wenn Class.equals() und Class.hashCode() nicht wie gewünscht funktionieren, benötigen Sie einen Wrapper, um das gewünschte Verhalten zu erreichen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X