2012-02-08 12 views
5

Ho difficoltà a fare questo lavoro:generici Java emissione Abstract Factory

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; 
    } 

} 

Il problema è un errore di compilazione:

Type mismatch: cannot convert from MapperFactory.MyTaskMapperFactory to MapperFactory

nel mio MapperFactory qui:

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

Qualsiasi idee su come risolvere questo errore?

Naturalmente la sostituzione:

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!"); 
    } 

avrebbe funzionato, ma che non è la risposta che sto cercando.

Questo sembra essere un problema con il modello generico di una fabbrica astratta in generale. Anche le risposte che forniscono esempi di origine usando oggetti personalizzati sono benvenute.

+0

'MAPPER' non è un nome di classe valido in seguito alle convenzioni Java. –

+0

Si prega di rendere i nomi delle classi il più piccoli possibile (ma ancora chiaro). E rinominare 'MAPPER' in' Mapper'? I nomi di classi strane/lunghe semplicemente confondono/ingombrano la domanda * e * le risposte. – Bohemian

+0

@Questo MAPPER non è un nome di classe. È il nome di Tipo generico come T in HashMap

risposta

4

Secondo Effective Java, 2nd edition, punto 28:

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

Il tuo metodo getMapperFactory utilizza solo il parametro di tipo M nel tipo di ritorno. A seguito di questo consiglio ha pronunciato la seguente firma di metodo, e il metodo compila:

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

EDIT: Più guardo il codice, più ci penso MapperFactory non deve essere parametrizzato. Il parametro non è usato nel codice qui, getTaskMapper restituisce un TaskMapper.

+2

Ancora più breve, la firma può essere semplicemente 'static statica MapperFactory getMapperFactory()'. Il metodo non vincola nessuno dei parametri di tipo più della firma della classe per "MapperFactory". Lo stesso dicasi per 'abstract TaskMapper pubblico getTaskMapper()'. (Potrebbe anche essere 'public abstract M getTaskMapper()', non può dire quale sia l'intento dietro il parametro type. * * In caso di dubbio, usare meno generici "* è probabilmente una buona regola empirica. – millimoose

1

L'istruzione return funziona bene con un typecast:

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

Quel codice non verrà mai eseguito anche se nella sua forma attuale, perché Bpm007PrepareDocTaskMapper non si estende BpmCommonMessageDto, in modo da MsgIn non può assolutamente essere un'istanza di Bpm007PrepareDocTaskMapper.

+0

Ho modificato la parte "if" per informazioni, che non era ancora finita e non è rilevante qui. Un modo per evitare i calchi? –

1

La mia soluzione sarebbe uccidendo il maggior numero di farmaci generici il più possibile con un fuoco:

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; 
    } 

} 

Non è davvero necessario ripetere i parametri di tipo di una classe in ogni metodo che utilizza, se non lo fai davvero a cuore ciò che sono o non hanno bisogno di vincolarli più di quanto faccia la firma della classe.