java DAO 设计模式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9954761/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DAO design pattern
提问by Mercurial
So lets say we have a couple of entities we want to persist using DAO objects. So we implement the right interface so we end up with
因此,假设我们有几个想要使用 DAO 对象持久化的实体。所以我们实现了正确的接口 所以我们最终得到
class JdbcUserDao implements UserDao{
//...
}
class JdbcAddressDao implements AddressDao{
//...
}
So if I want to be able to switch persistance implementations from JDBC to JPA (for example) and vice versa, I'd need to have JPAUserDao and JPAAddressDao... Meaning if I had 20 entities, and decided to switch implementations(using DI container), I'd have to switch every Jdbc implementation with JPA in code.
因此,如果我希望能够将持久性实现从 JDBC 切换到 JPA(例如),反之亦然,我需要有 JPAUserDao 和 JPAAddressDao ......这意味着如果我有 20 个实体,并决定切换实现(使用 DI容器),我必须在代码中使用 JPA 切换每个 Jdbc 实现。
Now it could be that I misunderstood how DAO works, but... If I just had
现在可能是我误解了 DAO 的工作原理,但是......如果我只是
class JdbcDaoImpl implements UserDao,AddressDao{
//...
}
I'd then have all the JDBC implementations in one class, and switching implementations would be a piece of cake. Also, DaoImpl count is equal to number of Dao interfaces. Why not just group them by implementation (jdbc, JTA, JPA...) and have everything under one class?
然后我会将所有 JDBC 实现放在一个类中,切换实现将是小菜一碟。此外,DaoImpl 计数等于 Dao 接口的数量。为什么不按实现(jdbc、JTA、JPA...)将它们分组并将所有内容都放在一个类下?
Thanks in advance.
提前致谢。
回答by Arjan Tijms
Having a single class implement every DAO interface in your entire application would be a rather bad design.
在整个应用程序中让单个类实现每个 DAO 接口将是一个相当糟糕的设计。
A more typical pattern is to have a BaseDAO
interface (also often called GenericDAO
) and have a JPABaseDAO
, JDBCBaseDAO
etc. These base classes will contain methods like find/get/read, save/store/persist, update/modify and delete/remove/purge.
更典型的模式是有一个BaseDAO
接口(也常被称为GenericDAO
),并有一个JPABaseDAO
,JDBCBaseDAO
等等。这些基类将包含类似查找方法/得/读取,保存/存储/坚持,更新/修改和删除/删除/清除。
Specific DAO interfaces like UserDAO
then inherit from BaseDAO
and concrete implementations like JPAUserDAO
extends from JPABaseDAO
.
特定的 DAO 接口(如UserDAO
then 继承自)BaseDAO
和具体的实现(如JPAUserDAO
extends from )JPABaseDAO
。
A BaseDAO
interface could look like this:
一个BaseDAO
界面看起来是这样的:
public interface BaseDAO <T> {
T getByID(Long ID);
T save(T type);
T update(T type);
void delete(T type);
}
And a UserDAO
interface:
和一个UserDAO
界面:
public interface UserDAO extends BaseDAO<User> {
List<User> getAllAuthorized();
}
Bare bones example of a JPABaseDAO
implementing this interface:
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));
}
}
And some sample UserDAO
implementation that would inherit from it:
以及一些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();
}
}
In practice the base class can often do some other things transparently, for instance checking if an entity implements some kind of Auditable
interface, and automatically setting the date and user that modified it, etc.
在实践中,基类通常可以透明地做一些其他的事情,例如检查实体是否实现了某种Auditable
接口,并自动设置修改它的日期和用户等。
When using EJB to implement your DAOs, one strategy to change implementations would be to put all JDBC implementations in one package and all JPA implementations in the other. Then just include only one implementation package in your build.
使用 EJB 实现 DAO 时,更改实现的一种策略是将所有 JDBC 实现放在一个包中,将所有 JPA 实现放在另一个包中。然后只在您的构建中包含一个实现包。
回答by A.H.
The whole point of Dependency Injection is to make switching between implementation easier and to decouple the user from the provider. Hence all DI frameworks provide some way to "group" several implementations (here your JDBC-group and your JPA-group) and switch them in one place.
依赖注入的全部意义在于使实现之间的切换更容易,并使用户与提供者解耦。因此,所有 DI 框架都提供了某种方法来“分组”多个实现(这里是您的 JDBC 组和 JPA 组)并将它们切换到一个地方。
Also: Usually the number of consumers (in your case: some business logic working on users and addresses) is usually higher than the number of DAOs the DI framework will uncouple most of the stuff for you anyway. Assume: 50 business beans, two interfaces and two implementations for each interface (4 total): even basic DI will take care for the 50. Using grouping will halve that remaining rest for you.
另外:通常消费者的数量(在您的情况下:一些处理用户和地址的业务逻辑)通常高于 DI 框架无论如何都会为您解耦大部分内容的 DAO 数量。假设:50 个业务 bean、两个接口和每个接口的两个实现(总共 4 个):即使是基本的 DI 也会处理这 50 个。使用分组将为您将剩余的剩余部分减半。
回答by bennidi
There are definitely possibilities to implement the DAO pattern in a widely technology agnostic way such that switching persistence technology or even mixing multiple technologies becomes feasible. This article presents one implementation scheme including source code on github.
绝对有可能以广泛的技术不可知方式实现 DAO 模式,这样切换持久性技术甚至混合多种技术变得可行。本文介绍了一种实现方案,包括github上的源代码。