DAO 和服务?
Posted
技术标签:
【中文标题】DAO 和服务?【英文标题】:DAO and Service? 【发布时间】:2012-01-06 14:10:28 【问题描述】:我总是面临一个问题,即我无法真正想到封装许多 DAO 方法的服务对象。
我的意思是,对于我的 servlet,有时使用单个 DAO 方法就足够了,例如 addUser(User params)。
更好的做法 - 用服务对象封装 DAO 方法并始终只使用服务对象,即使它的字面意思是单个服务方法调用单个 dao 方法或混合使用它们(一些方法来自服务对象,一些来自服务对象) servlet 上下文中的 dao)——这意味着我在控制器内部有自动装配的 DAO 和服务对象?
如果我开始在同一个地方同时使用 DAO 和 Service 对象,它会混淆逻辑吗?
【问题讨论】:
【参考方案1】:我认为这取决于情况。如果没有 DAO 会导致业务逻辑和数据访问逻辑混在一起,那么最好有单独的类。
但是,如果您的 DAO 是“虚拟的”并且只是调用 EntityManager 方法,您可能可以直接在您的服务对象中使用它。这个想法是让类具有single responsibilities 并且易于扩展和测试。你不应该为了它而创建图层。
如果您想保留可重用的服务层,我可能不会直接从您的控制器中使用 DAO。如果 DAO 没有意义,我宁愿在服务层使用 EntityManager(或您正在使用的任何持久性策略)。
【讨论】:
如果它是虚拟的,你是什么意思?我虽然那应该是怎样的? DAO 必须尽可能简单和虚拟?如果你做了复杂的 DAO,那可能是你已经把里面的业务逻辑搞混了? 如果您有一个简单地调用 EntityManager 方法的 DAO,就是这样,您为什么需要 DAO?为什么不直接使用 EntityManager?例如,如果我想使用标准 API 构建查询,我会使用 DAO,这可能需要很多行并且我不想与我的业务逻辑混在一起。 我感觉我在谈论不同的事情,我正在考虑这样一种情况:我们有 DAO 有一些访问数据库的方法。我们有服务对象单一方法,它只使用这个 DAO 中的单一方法来执行它的工作。当我们可以直接使用DAO方法时,在Service Object中创建一个只使用单个DAO方法的方法是否可行。你说的是同一件事吗?我有很多“EntityManager”方法。 我认为我们在谈论同一件事 :) 我仍然不喜欢直接从您的控制器调用 DAO 的想法(这就是我的理解)。我宁愿使用服务中的 EntityManager 而不是将 DAO 暴露给上层。 是的,没错!我需要检查。 :-) 回答你的问题:“你为什么需要 DAO?”因为 EntityManager 使用 dao 方法?你的 EntityManager 是什么? (我还没有使用 ORM 框架,对设计模式也不是很熟悉,是不是来自这些领域?)【参考方案2】:我正在使用“您不能让控制器与 DAO 交互!”的系统。设计理念在某一时刻被接受,并为每个组件创建了一个服务层。正如您所描述的,大多数服务只是简单地委托给 DAO。我反对这种哲学有两个原因。
一个是古老的“你不需要它”。在您需要之前不要实施某些东西。仅仅因为您预见到某些原因需要额外的间接层来执行一些额外的逻辑,因此不确定您是否需要它。当你最终需要它时,你可能会发现你的期望与你之前所相信的并不相符。而且你会得到额外的成本,因为现在你必须对两个类而不是一个类进行单元测试,而且你需要在两个地方而不是一个地方添加方法的情况并不少见。
第二个是,到底什么是服务?当我为我的领域建模时,我尝试用面向对象的术语来思考。有用户,因此 User 类是有意义的。有新闻项目,因此 NewsItem 类是有意义的。但我什至不知道 UserService 应该做什么。包含用户的“业务逻辑”?不,这就是 User 类的用途。
如果您需要对“外部世界”保持严格的 API,那么我可以看到一个案例,即拥有一个保持不变的额外层。但在所有其他情况下,您将不需要它。
【讨论】:
我觉得你在这里拉伸 YAGNI。按照你的逻辑,应该从从 servlet 触发查询开始,并且没有任何 DAO。我们不应该为维护而编写代码,因为您现在还没有遇到过。如果您的项目有多个服务,只是将调用委托给 DAO,我看到了开发中的一个严重缺陷。应该有一个共同的服务和 Dao 来处理普通的 CRUD。我同意你的 OOPS 概念,但我们在名词王国(检查goo.gl/EAZbX)。你可以说,我们可以做到这一点,但并非没有调试成本,有时还有代码重复。 @Adi:我承认我有点极端,但问题是服务何时简单地委托给 DAO,我觉得必须有人扮演魔鬼的拥护者。 servlet 之所以不直接触发查询,是因为我也相信单一职责原则。我认为我对“服务”的反感是,我见过的 90% 的示例要么只是将单个调用委托给另一个对象,要么包含更适合真实域对象的逻辑。哦,我喜欢阅读 Yegge 的帖子,即使我不同意。 :)【参考方案3】:就我个人而言,我通常将 DAO 调用封装在服务中。
这使我可以使用 AOP/etc 使所有服务都具有事务性。并在这些服务中使用非事务性 DAO 方法。
对于琐碎的服务,这是一个额外的“层”,但 IMO 是一个服务于目的的“层”(无论如何都可以使用一种或另一种代码生成来生成它)。不过,我仅将 DAO 功能封装在服务中也很少见。
【讨论】:
【参考方案4】:视情况而定。将 DAO 和 Service 层分开的原因通常是:
技术限制(参见其他答案中的 AOP 事务) 架构约束(DTO 服务层和 DAO 之间的 @Entities 转换) 历史性(这就是 X 年的做法) 美观(只有一层可从视图层访问)使用 Java EE 6 (JBoss AS 7),我没有这些负担:
无 AOP - @Stateless 和 @Transactional 负责事务。 没有 DTO - 我使用从 JPA 到视图层的 @Entities。 不要关心历史。 我更喜欢简洁/少代码而不是美观。所以我在 DAO 层有大多数方法。 对于某些更复杂的操作,我创建了一个服务 bean,并且可能使用了extended persistence context。
我的经验法则,方法是否应该进入 Service bean:
-
如果它使用多个 DAO(显然)
如果它执行多个实体管理器调用
如果实施可能发生变化,例如在 JPQL 与 Hibernate Search 与 ElasticSearch 中完成的搜索。
【讨论】:
以上是关于DAO 和服务?的主要内容,如果未能解决你的问题,请参考以下文章