让一个类实现整个应用程序中的每个 DAO 接口将是一个相当糟糕的设计。
更典型的模式是有一个BaseDAO 接口(也通常称为GenericDAO)并有一个JPABaseDAO、JDBCBaseDAO 等。这些基类将包含诸如查找/获取/读取、保存/存储/持久化、更新/修改和删除/移除/清除。
特定的 DAO 接口,如 UserDAO,然后继承自 BaseDAO,而具体的实现,如 JPAUserDAO,则继承自 JPABaseDAO。
BaseDAO 接口可能如下所示:
public interface BaseDAO <T> {
T getByID(Long ID);
T save(T type);
T update(T type);
void delete(T type);
}
还有一个UserDAO 接口:
public interface UserDAO extends BaseDAO<User> {
List<User> getAllAuthorized();
}
JPABaseDAO 实现此接口的简单示例:
@Stateless
public class JPABaseDAO<T> implements BaseDAO<T> {
@PersistenceContext
private EntityManager entityManager;
private final Class<T> entityType;
@SuppressWarnings("unchecked")
public JPABaseDAO() {
this.entityType = ((Class<T>) ((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<User> implements UserDAO {
@PersistenceContext
private EntityManager entityManager;
@Override
public List<User> getAllAuthorized() {
return entityManager.createNamedQuery("User.getAllAuthorized", User.class)
.getResultList();
}
}
在实践中,基类通常可以透明地做一些其他事情,例如检查实体是否实现了某种Auditable接口,并自动设置修改它的日期和用户等。
使用 EJB 实现 DAO 时,更改实现的一种策略是将所有 JDBC 实现放在一个包中,将所有 JPA 实现放在另一个包中。然后在你的构建中只包含一个实现包。