2011-05-23 14 views
31

Supongamos dos interfaces:fábrica genérico con clases de implementación desconocidos

public interface FruitHandler<T extends Fruit> 
{ 
    setFruit(T fruit); 
    T getFruit(); 
} 

public interface Fruit 
{ 
} 

Ahora quiero una fábrica para crear FruitHandlers (por ejemplo AppleHander, OrangeHandler, ...), pero el FruitHandlerFactory no sabe lo necesite acerca de la implementación clases de ambas interfaces (como en java parameterized generic static factory). El FruitHandlerFactory debería funcionar de esta manera (donde OrangeHandler implementa FruitHandler y Orange implementos Fruit):

FruitHandlerFactory fhf = new FruitHandlerFactory<OrangeHandler,Orange>(); 
OrangeHandler fh = fhf.create(); 
Orange orange = (Orange)fh.getFruit(); 

Esta debe ser la fábrica:

public class FruitHandlerFactory<A extends FruitHandler, B extends Fruit> 
{ 
    public FruitHandler create() 
    { 
     FruitHandler<Fruit> fh = new A<B>(); //<--- ERROR 
     fh.setFruit(new B()); 
     return fh; 
    } 
} 

Dónde consigo este error:

The type A is not generic; it cannot be parameterized with arguments <B> 

BTW: ¿Es posible hacer que el método create() sea estático?

+2

Excelente pregunta y gran fragmento de código para ilustrar. – sje397

Respuesta

39

Dado que los genéricos en Java se implementan usando borrado, la información de tipo FruitHandlerFactory no estará disponible en tiempo de ejecución, lo que significa que no puede instanciar A (o B) de esta manera.

Usted puede , sin embargo pasar de un objeto Class del tipo correcto para evitar este:

public class FruitHandlerFactory<H extends FruitHandler<F>, F extends Fruit> { 
    final Class<H> handlerClass; 
    final Class<F> fruitClass; 

    public FruitHandlerFactory(final Class<H> handlerClass, final Class<F> fruitClass) { 
     this.handlerClass = handlerClass; 
     this.fruitClass = fruitClass; 
    } 

    public H create() throws InstantiationException, IllegalAccessException { 
     H handler = handlerClass.newInstance(); 
     handler.setFruit(fruitClass.newInstance()); 
     return handler; 
    } 
} 

Un pequeño inconveniente es que usted tiene que escribir los nombres de los tipos tres veces (1) si desea crear una instancia de un FruitHandlerFactory:

FruitHandlerFactory fhf = new FruitHandlerFactory<OrangeHandler,Orange>(OrangeHandler.class, Orange.class); 

se puede reducir algo que produciendo un método staticcreateFactory() en su FruitHandlerFactory:

static <H extends FruitHandler<F>, F extends Fruit> FruitHandlerFactory<H, F> createFactory(
     final Class<H> handlerClass, final Class<F> fruitClass) { 
    return new FruitHandlerFactory<H, F>(handlerClass, fruitClass); 
} 

y utilizar de esta manera:

FruitHandlerFactory fhf = FruitHandlerFactory.createFactory(OrangeHandler.class, Orange.class); 
+0

Esto es increíble ... :-) ¡Gracias por esta respuesta excelente e integral! – Thor

2

De this question:

Quizás probar esto?

public class FruitHandlerFactory<A extends FruitHandler<B>, B extends Fruit> 
Cuestiones relacionadas