2012-02-08 11 views
5

estoy luchando para hacer este trabajo:genéricos de Java cuestión abstracta de fábrica

public abstract class MapperFactory<M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> { 

    public static <M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> MapperFactory<M> getMapperFactory(Message msgIn, Message msgOut) { 

     if (msgIn.isMyMapper()) 
      return new MyTaskMapperFactory(); 

     throw new IllegalStateException("Mapper not found!"); 
    } 

    public abstract TaskMapper<? extends Message, ? extends Message, ? extends TaskForm> getTaskMapper(); 

    public static class MyTaskMapperFactory extends MapperFactory<MyTaskMapper> { 

     @Override 
     public TaskMapper<? extends Message, ? extends Message, ? extends TaskForm> getTaskMapper() { 
      return new MyTaskMapper(); 
     } 

    } 
} 

public interface TaskMapper<I extends Message, O extends Message, F extends TaskForm> { 

    public F fillForm(I msgIn, O msgOut, F taskForm); 

    public O fillMsgOut(F taskForm); 
} 

public class MyTaskMapper implements TaskMapper<IncomingMessage, OutgoingMessage, MyTaskForm > { 

    public MyTaskForm fillForm(IncomingMessage msgIn, OutgoingMessage msgOut, 
      MyTaskForm taskForm) { 
     return null; 
    } 

    public OutgoingMessage fillMsgOut(MyTaskForm taskForm) { 
     return null; 
    } 

} 

El problema es un error de compilación:

Type mismatch: cannot convert from MapperFactory.MyTaskMapperFactory to MapperFactory

en mi MapperFactory aquí:

if (msgIn.isMyMapper()) 
      return new MyTaskMapperFactory(); 

Cualquier ideas de cómo solucionar este error?

Por supuesto la sustitución:

public static <M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> MapperFactory<M> getMapperFactory(Message msgIn, Message msgOut) { 

     if (msgIn.isMyMapper()) 
      return new MyTaskMapperFactory(); 

     throw new IllegalStateException("Mapper not found!"); 
    } 

con:

public static MapperFactory<?> getMapperFactory(Message msgIn, Message msgOut) { 

     if (msgIn.isMyMapper()) 
      return new MyTaskMapperFactory(); 

     throw new IllegalStateException("Mapper not found!"); 
    } 

quiere trabajar, pero que no es la respuesta que yo estoy buscando.

Esto parece ser un problema con el patrón genérico de fábrica abstracta en general. También se agradecen las respuestas que proporcionan muestras de origen utilizando objetos hechos a medida.

+0

'MAPPER' no es un buen nombre de clase siguiendo las convenciones de Java. –

+0

Por favor, haga que los nombres de su clase sean lo más pequeños posible (pero claros). ¿Y renombrar 'MAPPER' a' Mapper'? Los nombres de clase extraños/largos simplemente confunden/complican la pregunta * y * las respuestas. – Bohemian

+0

@his MAPPER no es un nombre de clase. Es el nombre del tipo genérico como T en HashMap

Respuesta

4

Según Effective Java, 2ª edición, artículo 28:

If a type parameter appears only once in a method declaration, replace it with a wildcard.

Su método getMapperFactory sólo se utiliza el parámetro M tipo en el tipo de retorno. Siguiendo este consejo da el siguiente método de firma, y ​​el método compila:

public static MapperFactory<? extends TaskMapper<Message, ? extends Message, ? extends String>> getMapperFactory(Message msgIn, Message msgOut) 

EDIT: Cuanto más miro el código, cuanto más pienso MapperFactory no debe ser parametrizado. El parámetro no se usa en el código aquí, getTaskMapper devuelve un TaskMapper.

+2

Aún más corto, la firma puede ser 'pública static MapperFactory getMapperFactory()'. El método no restringe ninguno de los parámetros de tipo más que la firma de clase para 'MapperFactory'. Lo mismo ocurre con 'Resumen público TaskMapper getTaskMapper()'. (También podría ser 'público abstracto M getTaskMapper()', no puede decir cuál es la intención detrás del parámetro de tipo.) * "En caso de duda, use menos genéricos" * es probablemente una buena regla empírica. – millimoose

1

La instrucción de retorno funciona bien con un encasillado:

return (BpmMapperFactory<MAPPER>)new Bpm007PrepareDocTaskMapperFactory(); 

Ese código no se ejecutará aunque en su forma actual, ya no se extiende Bpm007PrepareDocTaskMapper BpmCommonMessageDto, por lo MsgIn no puede ser una instancia de Bpm007PrepareDocTaskMapper.

+0

Edité la parte 'if', gracias por la información, que aún no estaba terminada y no es relevante aquí. ¿Alguna manera de evitar los moldes? –

1

Mi solución estaría matando la mayor cantidad de los medicamentos genéricos como sea posible con un fuego:

abstract class MapperFactory<M extends TaskMapper<?, ?, ?>> { 

    public static MapperFactory<?> getMapperFactory(Message msgIn, Message msgOut) { 
     if (msgIn.isMyMapper()) return new MyTaskMapperFactory(); 
     throw new IllegalStateException("Mapper not found!"); 
    } 

    public abstract M getTaskMapper(); 
} 


class MyTaskMapperFactory extends MapperFactory<MyTaskMapper> { 

    @Override 
    public MyTaskMapper getTaskMapper() { 
     return new MyTaskMapper(); 
    } 

} 


interface TaskMapper<I extends Message, O extends Message, F extends TaskForm> { 

    public F fillForm(I msgIn, O msgOut, F taskForm); 

    public O fillMsgOut(F taskForm); 

} 

class MyTaskMapper implements TaskMapper<IncomingMessage, OutgoingMessage, MyTaskForm> { 

    public MyTaskForm fillForm(IncomingMessage msgIn, OutgoingMessage msgOut, MyTaskForm taskForm) { 
     return null; 
    } 

    public OutgoingMessage fillMsgOut(MyTaskForm taskForm) { 
     return null; 
    } 

} 

En realidad no es necesario repetir los parámetros de tipo de una clase en todos los métodos que lo utiliza si no lo hace realmente les importa lo que son o no necesitan restringirlos más de lo que lo hace la firma de la clase.

Cuestiones relacionadas