因此,假设我们想要使用DAO对象保留几个实体。所以我们实现了正确的界面,所以我们最终得到了
class JdbcUserDao implements UserDao{
//...
}
class JdbcAddressDao implements AddressDao{
//...
}
因此,如果我希望能够将持久性实现从JDBC切换到JPA(例如),反之亦然,我需要拥有JPAUserDao和JPAAddressDao ......意思是如果我有20个实体,并决定切换实现(使用DI容器),我必须在代码中用JPA切换每个Jdbc实现。
现在可能是我误解了DAO是如何工作的,但是......如果我只是
class JdbcDaoImpl implements UserDao,AddressDao{
//...
}
然后,我将所有JDBC实现都放在一个类中,切换实现将是一件小事。此外,DaoImpl计数等于Dao接口的数量。为什么不通过实现(jdbc,JTA,JPA ......)对它们进行分组并将所有内容都放在一个类下?
提前致谢。
答案 0 :(得分:20)
在整个应用程序中使用单个类实现每个DAO接口将是一个相当糟糕的设计。
更典型的模式是拥有BaseDAO
接口(通常也称为GenericDAO
)并拥有JPABaseDAO
,JDBCBaseDAO
等。这些基类将包含类似的方法find / get / read,save / store / persist,update / modify and delete / remove / purge。
UserDAO
等特定DAO接口继承自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实现放在另一个包中。然后只在构建中包含一个实现包。
答案 1 :(得分:1)
依赖注入的重点是使实现之间的切换更容易,并将用户与提供者分离。因此,所有DI框架都提供了一些方法来“组合”多个实现(这里是您的JDBC组和JPA组)并将它们切换到一个位置。
另外:通常消费者的数量(在您的情况下:一些处理用户和地址的业务逻辑)通常高于DI框架将为您解开大部分内容的DAO数量。假设:每个界面有50个业务bean,两个接口和两个实现(总共4个):即使是基本的DI也会照顾50个。使用分组会将剩余的剩余时间减半。
答案 2 :(得分:0)
绝对有可能以广泛的技术不可知的方式实现DAO模式,使得切换持久性技术甚至混合多种技术变得可行。本文介绍了一种实现方案,包括github上的源代码。