2009-05-12 13 views
5

tengo código que se ve como sigue:Patrón de método de fábrica en Java usando genéricos, ¿cómo?

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

Ahora, sé que el código huele .. por muchas razones. Sin embargo, este código también está aquí: http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html, se refieren 9.8

Lo que intento hacer es lo siguiente: 1) Interruptor de mis DAOs implementaciones en tiempo de ejecución basado en el entorno (propiedades del sistema). 2) Hacer uso de los genéricos de Java para que pueda evitar la conversión de tipos ... , por ejemplo, hace algo como esto:

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

A diferencia:

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

sus ideas y sugerencias, por favor .

Respuesta

10

debe definir la fábrica así:

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 debe devolver un DAOFactory escrita a máquina adecuada.

La variable fábrica tendrá el tipo:

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

y el uso se escribe correctamente:

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

el único problema será probablemente un reparto requerido dentro de los métodos getInstance.

+0

¿Cómo puede tener 'List a = new ArrayList ();' y usarlo sin tener un método de fábrica que necesita un 'tipo de clase' como parámetro. Quiero hacer eso. –

0

Cuando he usado fábricas, he usado típicamente instanceof para determinar el tipo verdadero del objeto. Por ejemplo:

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

Esto se parece más limpio para mí, sobre todo si factory.getCustomerDAO() no devuelve nada cerca de un CustomerDAO (debido a cambios en la implementación).

Sólo mis dos centavos.

+0

cuál es el punto de la fábrica abstracta cuando ni siquiera está seguro de qué tipo de objetos generales (abstractos) devolverá. – javashlook

+0

Bien sabemos que devolverá algún tipo de BaseDAO, sin embargo, estamos tratando de entrar en el tipo verdadero subyacente del objeto y no su tipo declarado. – AlbertoPL

6

Hay un montón de artículos que detallan lo que necesita:

Tenga en cuenta que at, a diferencia de su ejemplo, no hay ninguna razón por la cual los métodos de DAOFactory no devuelvan las subclases reales (es decir, CustomerDAO getCustomerDAO()). Además, el beneficio principal del uso de DAO genéricos es tener el tipo de entidad "genericized", por lo que no tiene que emitir desde load()/get()/find() y métodos similares.

5

Su ejemplo no demuestra la necesidad de BaseDAO, y no hay ninguna razón por la cual DAOFactory.getCustomerDAO() no se debe declarar para que devuelva CustomerDAO. Entonces, realmente no veo la necesidad de genéricos allí. Sin embargo, tenga en cuenta lo siguiente:

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() { 
    ... 
    } 
} 

que he usado algo así como este enfoque en varios proyectos, y es muy agradable para escribir uno de DAO que funcione para todas las entidades en el modelo. La debilidad son los métodos de "búsqueda". Existen algunos enfoques claros, y el próximo trabajo en JPA es la estandarización de una API de "Criterios", pero por ahora a menudo es más fácil exponer los criterios del mecanismo de persistencia subyacente.

+0

Desafortunadamente, no puedo usar el enfoque de "un DAO funciona para cada entidad". No tengo permiso para usar JPA, hibernar o cualquier otro marco de persistencia/API. Mi problema aquí es evitar 50 Importaciones en mi DAOFactory (una para cada tipo de DAO que tengo - CustomerDAO, ItemDAO, etc.). Por lo tanto, la interfaz del marcador fue un intento desesperado de no devolver un DAO [XYZ] en cada método. ¿Qué sugieres en este escenario si quiero forzar el uso de genéricos? – Jay

Cuestiones relacionadas