Domanda

Ho domanda un Java generici Speravo che qualcuno potesse rispondere. Si consideri il seguente codice:

public interface Event{}
public class AddressChanged implements Event{}
public class AddressDiscarded implements Event{}

public interface Handles<T extends Event>{
    public void handle(T event);
}

Voglio realizzare questa interfaccia maniglie in questo modo:

public class AddressHandler implements Handles<AddressChanged>, Handles<AddressDiscarded>{
    public void handle(AddressChanged e){}
    public void handle(AddressDiscarded e){}
}

Ma Java non consente l'attuazione Maniglie due volte con il generico. Sono stato in grado di realizzare questo con C #, ma non riesco a capire una soluzione in Java senza l'utilizzo di riflessione o instanceof e la colata.

C'è un modo in Java per implementare le maniglie interfaccia utilizzando entrambe le interfacce generiche? O forse un altro modo di scrivere le maniglie interfaccia in modo che il risultato finale può essere realizzato?

È stato utile?

Soluzione

Non si può farlo in Java. È possibile implementare solo una realizzazione concreta della stessa interfaccia generica. Vorrei fare questo, invece:

public class AddressHandler implements Handles<Event>{
    public void handle(Event e){
      if(e instanceof AddressDiscarded){
         handleDiscarded(e);
      } else if(e instanceof AddressChanged){
         handleChanged(e);
      }
    }
    public void handleDiscarded(AddressDiscarded e){}
    public void handleChanged(AddressChanged e){}
}

Altri suggerimenti

Andando dopo @Amir Raminfar, è possibile utilizzare visitatore modello

interface Event{
 void accept(Visitor v);
}
interface Visitor {
 void visitAddressChanged(AddressChanged a);
 void visitAddressDiscarded(AddressDiscarded a);
}

class AddressChanged implements Event{
 @Override
 public void accept(Visitor v) {
  v.visitAddressChanged(this);
 } 
}

class AddressDiscarded implements Event{
 @Override
 public void accept(Visitor v) {
  v.visitAddressDiscarded(this);
 } 
}

class AddressHandler implements Visitor {
    void handle(Event e){
       e.accept(this);
     }
    public void visitAddressChanged(AddressChanged e){}
    public void visitAddressDiscarded(AddressDiscarded e){}
}

No, perché diversi "concrete" tipi generici in Java compilazione di dello stesso tipo . L'interfaccia reale l'oggetto implementerà è:

public interface Handles {
    public void handle(Event event);
}

E, ovviamente, non è possibile avere due metodi diversi, con una firma identica ...

Per quanto ne so non è possibile farlo, perché quando si compila il codice sorgente Java in questi saranno entrambi riducono a handle(Event), rendendo il metodo ambiguo.

Le informazioni generiche non è disponibile durante il runtime in Java, a differenza di C #. Ecco perché ci funziona come si descrive.

Si dovrà cambiare i nomi dei metodi per renderli unici, come handleAddressChanged e handleAddressDiscarded.

Questo è davvero uno dei punti deboli di generici Java.

Purtroppo no. La soluzione più comune (grasso, brutto, veloce) è creare un'interfaccia Handles (cioè HandlesAddressChange, HandlesAddressDiscarded) e assegna a ciascuno di essi un metodo differente (handleAddressChange(...), handleAddressDiscarded()).

In questo modo, il runtime Java può dire loro a parte.

In alternativa, è possibile utilizzare le classi anonime.

Non è consentito perché Java cancella firme generiche durante la compilazione. Il metodo di interfaccia sarà effettivamente avere la firma

public void handle(Object event);

Quindi, avete due scelte. O implementare gestori separati per i diversi eventi:

public class AddressChangedHandler implements Handles<AddressChanged>{ /* ... */ }
public class AddressDiscardedHandler implements Handles<AddressDiscarded>{ /* ... */ }

o implementare un gestore per tutti, ma controllare il tipo di evento in entrata:

public void handle(Event e){
  if (e instanceof AddressChanged) {
     handleAdressChanged(e);
  }
  else if (e instanceof AddressDiscareded) {
     handleAdressDiscarded(e);
  }
}

Un'implementazione come questo non funzionerà a causa dei vincoli della specifica Java. Ma se non hai paura di usare AOP o una sorta di un CIO-Container è possibile utilizzare le annotazioni per questo. Che i vostri aspetti o il contenitore potrebbe gestire l'infrastruttura di messaggistica e chiamare i metodi di annotare.

In primo luogo è necessario creare le annotazioni.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventConsumer {}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Handles{}

La si può annotare la classe del genere:

@EventConsumer
public class AddressHandler{
    @Handles
    public void handle(AddressChanged e){}
    @Handles
    public void handle(AddressDiscarded e){}
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top