2009-05-12 7 views
5

Ho codice che appare come segue:Modello di metodo di fabbrica in java con generici, come?

public interface BaseDAO{ 
// marker interface 
} 

public interface CustomerDAO extends BaseDAO{ 
public void createCustomer(); 
public void deleteCustomer(); 
public Customer getCustomer(int id); 
// etc 
} 

public abstract class DAOFactory { 
public BaseDAO getCustomerDAO(); 
public static DAOFactory getInstance(){ 
    if(system.getProperty("allowtest").equals("yes")) { 
    return new TestDAOFactory(); 
    } 
    else return new ProdDAOFactory(); 
} 

public class TestDAOFactory extends DAOFactory{ 
public BaseDAO getCustomerDAO() { 
    return new TestCustomerDAO(); // this is a concrete implementation 
    //that extends CustomerDAO 
    //and this implementation has dummy code on methods 
} 

public class ProdDAOFactory extends DAOFactory { 
public BaseDAO getCustomerDAO() { 
    return new ProdCustomerDAO(); // this implementation would have 
    // code that would connect to the database and do some stuff.. 
} 
} 

Ora, io so che questo codice odori .. per molte ragioni. Tuttavia, questo codice è anche qui: http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html, vedere 9.8

Ciò che intendo fare è questo: 1) Interruttore miei Tao implementazioni in fase di esecuzione in base all'ambiente (proprietà del sistema). 2) Sfruttate generici Java in modo che possa evitare di casting di tipo ... per esempio fa qualcosa di simile:

CustomerDAO dao = factory.getCustomerDAO(); 
dao.getCustomer(); 

Al contrario:

CustomerDAO dao = (CustomerDAO) factory.getCustomerDAO(); 
dao.getCustomer(); 

I vostri pensieri e suggerimenti, .

risposta

10

è necessario definire la fabbrica del genere:

public abstract class DAOFactory<DAO extends BaseDAO> { 
public DAO getCustomerDAO(); 
public static <DAO extends BaseDAO> DAOFactory<DAO> getInstance(Class<DAO> typeToken){ 
    // instantiate the the proper factory by using the typeToken. 
    if(system.getProperty("allowtest").equals("yes")) { 
    return new TestDAOFactory(); 
    } 
    else return new ProdDAOFactory(); 
} 

getInstance dovrebbe restituire un adeguato DAOFactory digitato.

La variabile fabbrica avrà il tipo:

DAOFactory<CustomerDAO> factory = DAOFactory<CustomerDAO>.getInstance(CustomerDAO.class); 

e l'utilizzo sarà correttamente digitato:

CustomerDAO dao = factory.getCustomerDAO(); 
dao.getCustomer(); 

l'unico problema sarà probabilmente un cast richiesto all'interno dei metodi getInstance.

+0

Come si può avere 'Elenco a = nuovo ArrayList ();' e usarlo senza avere un metodo factory che ha bisogno di un 'class type' come parametro. Voglio farlo. –

0

Quando ho utilizzato le factory, in genere ho usato instanceof per determinare il vero tipo dell'oggetto. Per esempio:

CustomerDAO dao; 
if (factory.getCustomerDAO() instanceof CustomerDAO) { 
    dao = factory.getCustomerDAO(); 
} 
dao.getCustomer(); 

Questo solo sembra più pulito per me, soprattutto se factory.getCustomerDAO() non restituisce nulla vicino a un CustomerDAO (a causa di cambiamenti di attuazione).

Solo i miei due centesimi.

+0

qual è il punto della fabbrica astratta quando non sei nemmeno sicuro di quale tipo (astratto) generale di oggetti tornerà. – javashlook

+0

Bene sappiamo che restituirà una sorta di BaseDAO, tuttavia stiamo cercando di ottenere il tipo vero sottostante dell'oggetto e non il suo tipo dichiarato. – AlbertoPL

6

C'è un gruppo di articoli che dettagliano quello che vi serve:

Si prega di notare a differenza del tuo esempio, non vi è alcun motivo per cui i metodi di DAOFactory non debbano restituire le sottoclassi effettive (ad es. CustomerDAO getCustomerDAO()). Inoltre, il vantaggio principale dell'utilizzo di DAO generici è il tipo di entità "generica", quindi non è necessario eseguire il cast da load()/get()/find() e metodi simili.

5

L'esempio non dimostra la necessità di BaseDAO e non vi è alcun motivo per cui DAOFactory.getCustomerDAO() non debba essere dichiarato per restituire un valore CustomerDAO. Quindi, non vedo davvero il bisogno di generici lì. Tuttavia, considerare quanto segue:

interface DataAccess<T> { 
    void store(T entity); 
    T lookup(Serialiable identifier); 
    void delete(Serializable identifier); 
    Collection<? extends T> find(Criteria query); 
} 

abstract class DataAccessFactory { 
    abstract DataAccess<T> getDataAccess(Class<T> clz); 
    static DataAccessFactory getInstance() { 
    ... 
    } 
} 

ho usato qualcosa di simile a questo approccio in diversi progetti, ed è molto bello di scrivere una DAO che funziona per ogni entità nel modello. La debolezza è il metodo del "cercatore". Esistono alcuni approcci accurati e il lavoro imminente in JPA è la standardizzazione di un'API "Criteria", ma per il momento è spesso più semplice esporre i criteri del meccanismo di persistenza sottostante.

+0

Sfortunatamente, non posso usare un approccio "DAO per ogni entità". Non sono autorizzato a utilizzare JPA, hibernate o qualsiasi altra struttura/API di persistenza. Il mio problema qui è di evitare 50 importazioni nel mio DAOFactory (uno per ogni tipo di DAO che ho - CustomerDAO, ItemDAO, ecc.). Quindi, l'interfaccia marker era un disperato tentativo di non restituire un DAO [XYZ] in ogni metodo. Cosa suggeriresti in questo scenario se voglio forzare l'uso di generici? – Jay