Шаблон фабричного метода в java с использованием дженериков, как это сделать?

StackOverflow https://stackoverflow.com/questions/855332

Вопрос

У меня есть код, который выглядит следующим образом:

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

Теперь я точно знаю, что этот код дурно пахнет..по многим причинам.Однако этот код есть и здесь:http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html, см. 9.8

То, что я намерен сделать, это:1) Переключайте мои реализации DAOs во время выполнения на основе среды (системные свойства).2) Используйте java generics, чтобы я мог избежать приведения типов...например, делает что-то вроде этого:

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

В отличие от:

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

Пожалуйста, ваши мысли и предложения.

Это было полезно?

Решение

Вы должны определить фабрику следующим образом:

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 должен возвращать правильно типизированный DAOFactory.

Заводская переменная будет иметь тип:

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

и использование будет правильно введено:

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

единственной проблемой, вероятно, будет приведение, требуемое внутри методов getInstance.

Другие советы

Там есть куча статей с подробным описанием того, что вам нужно:

Пожалуйста, обратите внимание, что, в отличие от вашего примера, нет причин, по которым методы DAOFactory не должны возвращать фактические подклассы (т.е. CustomerDAO getCustomerDAO()).Кроме того, основным преимуществом использования generic DAOs является наличие типа сущности "genericized", так что вам не нужно выполнять приведение из load()/get()/find() и подобные методы.

Ваш пример не демонстрирует необходимость в BaseDAO, и нет никакой причины , почему DAOFactory.getCustomerDAO() не должно быть объявлено, чтобы возвращать CustomerDAO.Так что на самом деле я не вижу там необходимости в дженериках.Однако учтите следующее:

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

Я использовал нечто подобное этому подходу в нескольких проектах, и очень приятно написать один DAO, который работает для каждого объекта в модели.Слабое место - это методы "поиска".Есть несколько аккуратных подходов, и предстоящая работа в JPA заключается в стандартизации API "Критериев", но на данный момент зачастую проще всего предоставить критерии базового механизма сохранения.

Когда я использовал фабрики, я обычно использовал instanceof для определения истинного типа объекта.Например:

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

Мне это просто кажется более чистым, особенно если factory.getCustomerDAO() не возвращает ничего близкого к CustomerDAO (из-за изменений в реализации).

Только мои два цента.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top