2015-05-19 17 views
6

ho questa classe astratta in cui ho definito alcuni metodi che implementano le azioni di database (recuperare le righe, inserimento, cancellazione, ecc)E 'cattiva pratica di restituire un generico all'interno di una classe astratta di diverso parametro generico

Ora Voglio fare un metodo che restituirà alcune righe (cioè l'intera tabella) ma invece delle classi di dominio voglio che restituisca le corrispondenti classi di modello (che fondamentalmente è lo stesso del dominio ma senza le liste di relazioni e altre cose che io indosso 'necessario per il livello di presentazione).

La classe astratta è

public abstract class DomainService<T extends Domain> { 

    protected abstract Logger getLogger(); 

    protected final Validator validator; 

    protected DomainService() { 
     ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 
     this.validator = factory.getValidator(); 
    } 

    abstract public void insert(T object) throws ValidationException; 

    abstract public void delete(T object) throws EntityNotFoundException; 

    abstract public List<T> fetchAll(); 
} 

e voglio aggiungere un altro metodo che chiamerà fetchAll() e poi iterare ogni elemento e creare il modello equivalente e tornare che lista.

public <K extends Model> List<K> fetchAllModels(Class<K> modelClass) { 
     List<T> domains = fetchAll(); 
     List<K> models = new ArrayList<K>(domains.size()); 

     for (T domain : domains) { 
      K model = modelClass.newInstance(); 
      models.add(model.fillIn(domain)); 
     } 

     return models; 
    } 

ignorando che questo è il codice che però solo ora a scrivere la domanda, è accettabile per aggiungere un parametro per un generico che non è definito nella classe. Una classe IMO può avere metodi che restituiscono altri tipi di dati, quindi non dovrebbe essere un problema. Nel mio caso passo la classe così posso creare un'istanza del modello e quindi utilizzare il dominio per riempire i membri. Ero di due pareri,

  • Quello che ho scritto in cui aggiungo un metodo alla classe del modello per creare è di per sé dalla oggetto di dominio. Stavo pensando a un costruttore che prende l'oggetto dominio come argomento, ma penso che sia un po 'una seccatura chiamare un costruttore che usa i generici (Avrebbe bisogno di utilità di riflessione per lo meno) quindi ho pensato a un metodo per riempire il dettagli dopo aver creato un'istanza utilizzando il costruttore predefinito. Anche il modello si trova su un livello superiore e penso che gli strati superiori dovrebbero usare quelli inferiori (Database-> Classi di dominio-> Classi di accesso (DAO) -> Classi di servizio-> Classi servlet ----> JSP che mostra i dati)

  • potrei aggiungere un metodo alla classe di dominio che trasforma il dominio al suo modello e chiamare che, senza dover passare alla classe del modello

    public <K> List<K> fetchAllModels() { 
        List<T> domains = fetchAll(); 
        List<K> models = new ArrayList<K>(domains.size()); 
    
        for (T domain : domains) { 
         models.add(domain.createModel()); 
        } 
    
        return models; 
    } 
    

ma sento che la classe di dominio dovrebbe essere il più pulire una rappresentazione della tabella nel database con gli unici metodi che hanno a che fare con le colonne.

Sarebbe meglio aggiungere il parametro alla classe. Sto solo andando a usarlo per questo metodo ...

qualsiasi pensiero commenti sempre graditi

+0

Non so se ti ho preso, ma sì; se si dispone di parametri di tipo che sono richiesti solo per i singoli metodi; allora dovresti farlo in quel modo - non c'è bisogno di renderlo un parametro di classe. – GhostCat

+1

Correggetemi se ho torto, ma penso che l'opzione B non possa funzionare a causa dell'inferenza di tipo, come può il compilatore Java dedurre il tipo _K_ dato solo le informazioni sul tipo _T_? – superbob

+0

Ignorare quanto sopra, ho confuso le domande. K estende Model, che è la classe astratta di base. E domain # createModel restituisce il tipo di modello. –

risposta

4

è accettabile per aggiungere un parametro per un generico che non è definito nella classe

Assolutamente. È fatto tutto il tempo

Preferisco la prima soluzione, passando il modello al metodo.

Ma, quello che vuoi veramente è una funzione che crea K da T. In java8, questo può essere fatto in modo molto sintetico.

public <K extends Model> List<K> fetchAllModels(Function<T,K> func) { 
... 
      K model = func.apply(domain); 

e dire di avere un modello 'M' per il dominio 'D'

public M(D domain) // constructor 

è possibile passare al costruttore come func (o almeno così sembra)

service.fectchAllModels(M::new) 

Se si utilizza Stream, fetchAllModels() diventa molto più semplice

abstract public Stream<T> fetchAll(); 

public <K extends Model> Stream<K> fetchAllModels(Function<T,K> func) { 
    return fetchAll().map(func) 
} 

E poi, perché abbiamo anche bisogno di questo metodo? Basta fare

// fetch domains, convert each to M 
Stream<M> models = service.fetchAll().map(M::new); 

Così possiamo rimuovere fetchAllModels(), e rimuovere tutte le dipendenze del modello da dominio.

+0

Grazie. Io uso Java 7, ma lo terrò a mente –

Problemi correlati