DAO和Service是什么?

12

我一直面临一个问题,就是无法想到包含许多DAO方法的服务对象的封装方式。

我的意思是对于我的servlet,有时使用单个DAO方法就足够了,例如 addUser(User params)。

应该怎么做——将DAO方法封装在服务对象中,并始终仅使用服务对象,即使这实际上意味着单个服务方法调用单个dao方法或在servlet上下文中混合使用它们(某些来自服务对象的方法和一些来自dao) - 这意味着我已经在控制器中自动连接了DAO和Service对象?

如果我开始在同一个地方同时使用DAO和服务对象,那么它会混淆逻辑吗?

4个回答

7

我认为这取决于具体情况。如果没有DAO将导致业务逻辑和数据访问逻辑混淆,那么最好有单独的类。

然而,如果你的DAO是“虚拟”的,只是调用EntityManager方法,那么你可能可以直接在服务对象中使用它。想法是有单一职责的类,易于扩展和测试。你不应该仅仅为了创建层级而创建层级。

如果您想保持可重用的服务层,则我可能不会直接从控制器中使用DAO。如果DAO没有意义,我宁愿在服务层中使用EntityManager(或任何您正在使用的持久化策略)。


如果它是虚拟的,你是什么意思?我认为这就是它应该的样子吧?DAO必须尽可能简单和虚拟?如果你制作复杂的DAO,那么很可能你已经混淆了业务逻辑的内部? - Aubergine
2
如果你有一个DAO只是调用EntityManager的方法,那么为什么需要DAO呢?为什么不直接使用EntityManager呢?例如,如果我想使用criteria API构建查询,这可能需要很多行代码,而我不想与业务逻辑混淆,那么我会使用DAO。 - Gonzalo Garcia Lasurtegui
2
我感觉我在谈论不同的事情,我正在考虑这样一个情况:我们有DAO有一些方法来访问数据库。我们有服务对象单个方法,它仅使用此DAO中的单个方法来执行其工作。当我们可以直接使用DAO方法时,在Service Object中创建仅使用单个DAO方法的单个方法是否可行?你说的是同样的事情吗?我有很多'EntityManager'方法。 - Aubergine
1
我认为我们在谈论同一件事 :) 我仍然不喜欢直接从控制器调用DAO的想法(这是我的理解)。 我宁愿使用服务中的EntityManager而不是将DAO暴露给上层。 - Gonzalo Garcia Lasurtegui
没错,确实需要检查一下。 :-) 对于你的问题:“你为什么需要DAO?”是因为EntityManager使用dao方法吗?那么你的EntityManager是什么呢?(我还没有使用ORM框架,并且对设计模式也不太熟悉,它是来自这些领域吗?) - Aubergine
当我说EntityManager时,我指的是JPA的EntityManager。这不是你创建的对象,它随JPA实现一起提供,比如Hibernate。 - Gonzalo Garcia Lasurtegui

5
我正在使用一个系统,在这个系统中,"你不能让控制器与DAO交互!"的设计理念被采纳,并为每个组件创建了一个服务层。正如你所描述的,大多数服务只是委托给DAO。我反对这种哲学有两个原因。
一个是老生常谈的"你不会需要它"。在需要之前不要实现它。仅仅因为你预见到需要多一层间接性来执行一些额外的逻辑,并不意味着你一定需要它。当你最终需要它时,你可能会发现你的期望并不完全符合你之前所认为的。而且你还要付出额外的成本,因为现在你必须单元测试两个类而不是一个,而且很常见的情况是你需要在两个地方添加方法而不是一个。
第二个原因是,到底什么是服务?当我建模时,我尝试以面向对象的方式思考。有用户,因此User类是有意义的。有新闻项目,因此NewsItem类是有意义的。但我甚至不知道UserService应该做什么。包含用户的“业务逻辑”吗?不,这就是User类存在的目的。
如果你需要维护一个严格的API给“外部世界”,那么我可以看到有一个额外的层保持不变。但在所有其他情况下,你不会需要它。

1
我觉得你在这里过度使用YAGNI。按照你的逻辑,应该从servlet开始发出查询而不是拥有任何DAO。我们不应该为维护编写代码,因为你现在还没有遇到它。如果你的项目有多个服务只是将调用委托给DAO,我认为开发中存在严重缺陷。应该有一个通用的服务和Dao来处理普通的CRUD操作。我同意你的OOPS概念,但我们处于名词王国(请参阅http://goo.gl/EAZbX)。你可以说,我们可以做到这一点,但代价是调试和有时代码重复。 - Adisesha
1
@Adi: 我承认我有点极端了,但问题是关于服务仅仅委派给DAO时的情况,我觉得必须有人担任魔鬼的代言人。Servlet没有直接触发查询的原因是因为我也相信单一职责原则。我对“服务”反感的原因是因为我看到的90%的示例要么只是将单个调用委托给另一个对象,要么包含最好适合于真实领域对象的逻辑。哦,我很喜欢阅读Yegge的文章,即使我不同意他的观点。 :) - waxwing

3

视情况而定。通常分离DAO和服务层的原因有:

  • 技术限制(参见其他答案中的AOP事务)
  • 架构限制(在服务层和DAO之间进行DTO <=> @Entities转换)
  • 历史原因(多年来一直这样做)
  • 美学原因(只从视图层访问一个层)

使用Java EE 6(JBoss AS 7),我没有这些负担:

  • 没有AOP - @Stateless和@Transactional处理事务。
  • 没有DTOs - 我在JPA中使用@Entities到视图层。
  • 不关心历史。
  • 我更喜欢简单 / 更少的代码而不是美学。

因此,我将大多数方法放在DAO层。 对于某些情况下的更复杂操作,我会创建一个服务bean,并可能使用扩展持久性上下文

我的经验法则是,方法是否应该进入服务bean:

  1. 如果它使用多个DAO,则很明显
  2. 如果它执行多个实体管理器调用
  3. 如果实现可能会改变,例如在JPQL中完成的搜索与Hibernate Search vs ElasticSearch。

3

个人而言,我通常将DAO调用封装在服务中。

这使得我可以使用AOP / etc.使所有服务具有事务性,并在这些服务中使用非事务性DAO方法。

对于琐碎的服务来说,这是一个额外的“层”,但我认为它是有意义的(无论如何,某种类型的代码生成都可以用于生成它)。虽然我很少只有DAO功能封装在一个服务中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接