サードパーティの ORM (Hibernate、JPA など) を簡単に切り替えられるように、DAO レイヤーに一般的なデザイン パターンを適用したいと考えています。どうやら、次のようなすべての DAO に共通のメソッドがいくつかあります。
- public void create(T エンティティ);
- public void update(T エンティティ);
- public void delete(オブジェクト pk);
- public T read(オブジェクト 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() {}
}
その後、異なる ORM をスムーズに切り替えられるようにする DAOFactory を作成します。
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();
}
次に、休止状態またはその他のプラグ可能な 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) を呼び出す方法を知りたいです。