在整个应用程序中使用单个类实现每个DAO接口将是一个相当糟糕的设计.
一个更典型的模式是拥有一个BaseDAO接口(通常也称为GenericDAO),并且有一个JPABaseDAO,JDBCBaseDAO等.这些基类将包含find / get / read,save / store / persist,update / modify和delete / remove等方法/清除.
特定的DAO接口,如UserDAO然后继承自BaseDAO,具体的实现,如JPAUserDAO从JPABaseDAO扩展.
BaseDAO接口可能如下所示:
public interface BaseDAO {
T getByID(Long ID);
T save(T type);
T update(T type);
void delete(T type);
}
还有一个UserDAO界面:
public interface UserDAO extends BaseDAO {
List getAllAuthorized();
}
实现此接口的JPABaseDAO的裸体实例:
@Stateless
public class JPABaseDAO implements BaseDAO {
@PersistenceContext
private EntityManager entityManager;
private final Class entityType;
@SuppressWarnings("unchecked")
public JPABaseDAO() {
this.entityType = ((Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
@Override
public T getByID(Long ID) {
return entityManager.find(entityType, ID);
}
@Override
public T save(T type) {
return entityManager.persist(type);
}
@Override
public T update(T type) {
return entityManager.merge(type);
}
@Override
public void delete(T type) {
entityManager.remove(entityManager.contains(type) ? type : entityManager.merge(type));
}
}
还有一些从它继承的示例UserDAO实现:
@Stateless
public class JPAUserDAO extends JPABaseDAO implements UserDAO {
@PersistenceContext
private EntityManager entityManager;
@Override
public List getAllAuthorized() {
return entityManager.createNamedQuery("User.getAllAuthorized", User.class)
.getResultList();
}
}
实际上,基类通常可以透明地做一些其他的事情,例如检查一个实体是否实现某种可审计接口,并自动设置修改日期和用户等等.
当使用EJB来实现DAO时,改变实现的一个策略是将所有JDBC实现放在一个包中,将所有JPA实现放在另一个包中.然后只需在构建中只包含一个实现包.