Factory method pattern in java using generics, how to?

25,866

Solution 1

You should define the factory like that:

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 should return a proper typed DAOFactory.

The factory variable will have the type:

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

and the usage will be properly typed:

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

the only problem will probably be a cast required inside the getInstance methods.

Solution 2

There's a bunch of articles detailing what you need:

Please note that, unlike your example, there is no reason why the methods of DAOFactory should not return the actual subclasses (i.e. CustomerDAO getCustomerDAO()). Furthermore, main benefit of using generic DAOs is having the entity type "genericized", so you don't have to cast from load()/get()/find() and similar methods.

Solution 3

Your example doesn't demonstrate a need for BaseDAO, and there is no reason why DAOFactory.getCustomerDAO() shouldn't be declared to return a CustomerDAO. So, I don't really see a need for generics there. However, consider the following:

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

I've used something like this approach in several projects, and it is very nice to write one DAO that works for every entity in the model. The weakness is the "finder" methods. There are some neat approaches, and upcoming work in JPA is standardizing a "Criteria" API, but for now it is often easiest to expose the underlying persistence mechanism's criteria.

Share:
25,866
Jay
Author by

Jay

geek, software developer, movie buff and pirate.

Updated on December 29, 2020

Comments

  • Jay
    Jay over 3 years

    I have code that looks like follows:

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

    Now, I do know that this code smells.. for many reasons. However, this code is here too: http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html, refer 9.8

    What I intend to do is this: 1) Switch my DAOs implementations at runtime based on environment (system properties). 2) Make use of java generics so that I can avoid type casting... for instance does something like this:

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

    As opposed to:

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

    Your thoughts and suggestions, please.