如何使用GenericDAO工厂设计模式?

时间:2013-05-16 08:54:40

标签: design-patterns generics factory-pattern genericdao

我想为我的DAO层应用通用设计模式,这样我就可以轻松地在第三方ORM之间切换(Hibernate,JPA等)。显然我们有一些适用于所有DAO的常用方法,如:

  • public void create(T entity);
  • public void update(T entity);
  • public void delete(Object pk);
  • public T read(Object pk);
  • public list readAll();

所有DAO都必须继承这些方法以及特定于每个DAO的其他方法,我发现以下设计模式适合我,但我不知道如何使用它以便拥有所有常用方法和专用方法在相同的DAO参考:

首先,我们将为所有常用方法创建一个接口:

public interface GenericDAOINT<T> {

    public void create(T entity);

    public void update(T entity);

    public void delete(Object pk);

    public T read(Object pk);

    public List<T> readAll();

}

我们将创建一个实现该接口的抽象类:

public abstract class GenericDAOHibernate<T> implements GenericDAOINT<T> {
    private Class<T> persistentClass;
    private Session session;
    private static SessionFactory sessionFactory;
    private static Logger LOGGER = Logger.getLogger("InfoLogging");

    public GenericDAOHibernate(T theClass) {
        this.persistentClass = (Class<T>) theClass;
        session = sessionFactory.openSession();
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    public void setPersistentClass(Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    static {
        sessionFactory = new Configuration().configure("hibernate.cfg.xml")
                        .buildSessionFactory();
    }

    public Session getSession() {
        return session;
    }

    public void create(T entity) {
        // implementation
    }

    public void update(T entity) {}

    public void delete(Object pk) {}

    public T read(Object pk) {}

    public List<T> readAll() {}
}

之后我们将制作一个DAOFactory,使我能够顺利地在不同的ORM之间切换:

public abstract class DAOFactory {
    public static DAOFactory getInstance(Class factory) {
        try {
            return (DAOFactory) factory.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Couldn't create DAOFactory: " + factory);
        }
    }
    // return reference to any desired dao in order to call specialized methods
    public abstract RegionHome getRegionDAO();
    public abstract ServicesHome getServicesDAO();
    public abstract StatusHome getStatusDAO();
}

接下来,我们将为hibernate或任何其他可插入的ORM创建一个DAOFactory:

public class DAOFactoryHibernate extends DAOFactory {

    public GenericDAOHibernate<?> instantiateDAO(Class<?> daoClass)
    {
        try
        {
            GenericDAOHibernate<?> dao = (GenericDAOHibernate<?>) daoClass.newInstance();    // Exception is thrown here
            return dao;
        } catch (Exception e) {
            System.out.println(e.toString());
            throw new RuntimeException("Can not instantiate DAO: " + daoClass, e);
        }
    }

    @Override
    public RegionHome getRegionDAO() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public ServicesHome getServicesDAO() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public StatusHome getStatusDAO() {
        // TODO Auto-generated method stub
        return null;
    }
}

为了为每个DAO添加特化,我们将为每个DAO创建一个接口,该接口将扩展GenericDAOINT以包含ServicesDAO的每个DAO中的常用方法,我们将执行以下操作:

public interface ServicesDAO<T> extends GenericDAOINT<ServicesHome> {

    public void specializedMethod();

}

最后我们将为Hibernate特定的ServicesDAO创建一个具体的类,如下所示:

public class ServicesDAOHibernate extends GenericDAOHibernate implements ServicesDAO {

    public ServicesDAOHibernate(Class theClass) {
        super(theClass);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void specializedMethod() {
        System.err.println("Specialized Method");
    }

}

我认为这些模式有助于在ORM之间轻松灵活地切换,但另一方面我告诉你的是我想在每个DAO的相同引用上调用所有方法(Common + Specialized),我试过以下客户端代码:

public class test {
    public static void main(String args[]) {

    DAOFactoryHibernate DFH = (DAOFactoryHibernate) DAOFactory.getInstance(DAOFactoryHibernate.class);
    ServicesDAOHibernate serviceObjectDAO=(ServicesDAOHibernate) DFH.instantiateDAO(ServicesDAOHibernate.class);
    serviceObjectDAO.specializedMethod();

}

但我得到以下例外:

Exception in thread "main" java.lang.RuntimeException: Can not instantiate DAO: class ServicesDAOHibernate
    Caused by: java.lang.InstantiationException: ServicesDAOHibernate
    at java.lang.Class.newInstance0(Class.java:340)
    at java.lang.Class.newInstance(Class.java:308)
    at DAOFactoryHibernate.instantiateDAO(DAOFactoryHibernate.java:9)

我想知道如何在相同的引用上调用所有方法(Common + Specialized),就像之前的客户端代码一样。

1 个答案:

答案 0 :(得分:1)

我希望你能发布完整的堆栈跟踪(你错过了导致问题的根本原因)。但是从查看代码开始,您的问题似乎是通过ServicesDAOHibernateClass.newInstance()上调用无参数构造函数,并且该类没有no-arg构造函数。你想用

return (GenericDAOHibernate<?>) daoClass.getConstructor(Class.class)
  .newInstance(daoClass);