Pregunta

Tengo una pregunta Java genéricos Tenía la esperanza de que alguien pudiera responder. Considere el siguiente código:

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

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

Quiero implementar esta interfaz se maneja como esto:

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

Sin embargo, Java no permite la implementación de manijas dos veces utilizando el genérico. Yo era capaz de lograr esto con C #, pero no puedo imaginar una solución en Java sin necesidad de utilizar la reflexión o instanceof y fundición.

¿Hay alguna manera en Java para implementar las manijas de interfaz con las dos interfaces genéricas? O tal vez otra manera de escribir las manijas interfaz para el resultado final se puede lograr?

¿Fue útil?

Solución

No se puede hacer eso en Java. Sólo se puede poner en práctica una realización concreta de la misma interfaz genérica. Me gustaría hacer esto en su lugar:

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){}
}

Otros consejos

Ir tras @Amir Raminfar, puede utilizar visitante patrón

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, porque diferentes "concretas" tipos genéricos en Java compilación a el mismo tipo . La interfaz real de su objeto implementará es:

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

Y, obviamente, no se puede tener dos métodos diferentes con una firma idéntica ...

Que yo sepa no se puede hacer eso, porque al compilar el código fuente en Java tanto estos se reducen a handle(Event), por lo que el método ambiguo.

La información genérica no está disponible durante el tiempo de ejecución en Java, a diferencia de C #. Por eso hay que funciona como usted describe.

tendrá que cambiar los nombres de los métodos para que sean únicos, como handleAddressChanged y handleAddressDiscarded.

Este es de hecho uno de los puntos débiles de los genéricos de Java.

Por desgracia, no. La solución habitual (grasa, feo, rápido) es crear una interfaz Handles (es decir HandlesAddressChange, HandlesAddressDiscarded) y dar a cada uno de ellos un método diferente (handleAddressChange(...), handleAddressDiscarded()).

De este modo, el tiempo de ejecución de Java puede distinguirlos.

O bien, puede utilizar las clases anónimas.

No está permitido porque Java borra firmas genéricas durante la compilación. El método de interfaz realmente tendrá la firma

public void handle(Object event);

Así que tienes dos opciones. O bien implementar controladores separados para diferentes eventos:

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

o implementar un controlador para todos, pero comprobar el tipo de evento entrante:

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

Una implementación de este tipo no funcionará debido a las limitaciones de la especificación Java. Pero si usted no tiene miedo de usar AOP o algún tipo de COI-Container podría utilizar anotaciones para eso. De sus aspectos o el contenedor podría gestionar la infraestructura de mensajería y llamar a los métodos que anotar.

En primer lugar hay que crear las anotaciones.

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

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

El que puede anotar su clase así:

@EventConsumer
public class AddressHandler{
    @Handles
    public void handle(AddressChanged e){}
    @Handles
    public void handle(AddressDiscarded e){}
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top