【问题标题】:How to use factory design pattern with GenericDAO?如何在 GenericDAO 中使用工厂设计模式?
【发布时间】:2013-05-11 02:03:09
【问题描述】:

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

  • 公共无效创建(T 实体);
  • 公共无效更新(T 实体);
  • public void delete(Object pk);
  • 公共T读取(对象pk);
  • 公共列表 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 以包含每个 DAO 中用于 ServicesDAO 的通用方法,我们将执行以下操作:

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)。

【问题讨论】:

  • JPA 已经是各种实现(EclipseLink、Hibernate 等)之上的通用抽象层。为什么要再添加一层?更改 ORM 的概率是多少,为什么不等待这个极不可能的事件来重构代码?雅格尼!
  • 由于某些原因,我现在必须使用休眠,但我想在它上面添加一个可插拔层,以便将来切换到另一个 ORM
  • 如您所见,我的 DAOFactory 为我添加了一个抽象,因为我可以像使用 DAOFactoryHibernate 一样添加任何 ORM 特定的实现

标签: design-patterns generics factory-pattern genericdao


【解决方案1】:

我希望您已经发布了完整的堆栈跟踪(您错过了导致问题的根本原因的原因)。但是从查看您的代码来看,您的问题似乎是您通过Class.newInstance()ServicesDAOHibernate 上调用无参数构造函数,而该类没有无参数构造函数。你想用

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-22
    • 2011-11-20
    相关资源
    最近更新 更多