views:

3157

answers:

4

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.

A: 

When I've used factories I've typically used instanceof to determine the true type of the object. For example:

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

This just seems cleaner to me, especially if factory.getCustomerDAO() doesn't return anything close to a CustomerDAO (due to changes in implementation).

Just my two cents.

AlbertoPL
what's the point of abstract factory when you're not even sure what general (abstract) type of objects will it return.
javashlook
Well we know it will return some sort of BaseDAO, however we're trying to get into the underlying true type of the Object and not its declared type.
AlbertoPL
+3  A: 

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.

javashlook
+3  A: 

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.

erickson
Unfortunately, I cannot use a 'one DAO works for every entity' approach. I am not allowed to use JPA, hibernate or any other persistence framework / API. My problem here is to avoid 50 Imports in my DAOFactory (one for every type of the DAO I have - CustomerDAO, ItemDAO, etc). Hence, the marker interface was a desperate attempt to not return a [XYZ]DAO in each method. What would you suggest in this scenario if I want to force using generics?
Jay
A: 

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.

Toader Mihai Claudiu