【问题标题】:How to wire a Service that depends on more than its own Repository?如何连接不仅仅依赖于自己的存储库的服务?
【发布时间】:2020-08-01 07:29:04
【问题描述】:

我正在开发一个标准的 Spring Boot(带有 Spring Web 和 Spring Data)Rest Web 服务并遇到了这种情况。

例如,如果我有两个实体:

  • 用户
  • 团队

他们有一个多对多的关系。他们的服务看起来如何?

选项 1:

  • UserService 依赖于 UserRepository
  • TeamService 依赖于 TeamRepository 和 UserRepository

选项 2:

  • UserService 依赖于 UserRepository
  • TeamService 依赖于 TeamRepository 和 UserService

我在考虑选项 2,因为每个存储库都通过其各自的服务进行接口,但以下问题来自于此:

如果我希望服务仅公开 DTO,并且需要我的 TeamService 中的用户实体,以便使用 Hibernate 进行多对多工作(我不仅需要 id 参考)。我必须做变通方法或从 UserService 公开实体。

什么是更清晰的解决方案,或者我的逻辑是否混淆了?

编辑:

一些上下文:

如果我需要 TeamService 中的 addUserToTeam(Integer userId, Integer teamId) 之类的方法,我需要通过 id 获取用户实体,以便将其添加到用户的团队列表中。

【问题讨论】:

  • 为什么teamService需要依赖其中一个?它们的功能将是相互排斥的。
  • 如果我需要 TeamService 中的 addUserToTeam(Integer userId, Integer teamId) 之类的方法,我需要通过 id 获取用户实体,以便将其添加到用户团队列表中。

标签: java spring spring-boot


【解决方案1】:

It depends。取决于您的业务用例..规则...

TeamUser 之间是否有某种所有者?

在将用户推入内部之前,您的企业是否需要创建团队?还是让用户以独立的方式创建?

也许当你必须创建一个用户时,你必须为他分配一个团队..也许不是..

假设您必须先创建一个Team,然后再将Users 添加到您现在可以将Team 视为一个聚合概念(查看领域驱动设计聚合)。

DDD 聚合是可以被视为单个单元的域对象集群。

这些对象也是如此:

  • 实体/值对象:团队、用户
  • 存储库:团队存储库
  • 服务:团队服务

所以“在这种情况下”不需要USerService or UserRepo。每次您想要添加/删除/更新用户时,您都将通过Teamobject/aggregate 来完成。因此新的User 的注册将通过

team.addUser(user);
teamRepository.update(team team)

如果现在这两个概念完全独立,您可以将它们视为 2 个独立的聚合体,并且两者都有自己的存储库。

关于服务作为团队和用户是相关的概念,有两个服务可能是矫枉过正。

维持TeamUsers 之间的生命周期和一致性的单一服务听起来更合适。

所以:

  • 实体/VO:团队、用户
  • 存储库:TeamRepository、UserRepository
  • Service : XXXService(XXX 替换为您选择的名词)

我只是说one service = one aggregate不是规则...服务是门面,门面可以包装一个由多个聚合组成的域模型。Keep cohesion high是规则。

【讨论】:

  • 很有趣,但在我的情况下,用户和团队是两个独立的聚合体,可以单独存在。我有与 UserService 中的用户和 TeamService 中的团队的业务逻辑相关的操作。您可以说关系的所有者是团队,因为团队由用户组成。团队不需要有用户,用户也不需要在一个团队中。
  • 实际上这取决于可用操作的数量。如果它是一个简单的 CRUD,只需一个外观少于 10 个操作就可以完成这项工作,而不会引入糟糕的耦合或更少的内聚。想想实用主义
  • 我不确定我是否理解你(我知道门面是什么)。你能用一个例子或更具描述性的解释来详细说明
  • 我只是说one service = one aggregate不是一个规则......服务是门面,门面可以包装一个由多个聚合组成的域模型。保持cohesion high 是规则。
  • 您能否将最后一条评论添加到您的答案中以使其更清晰。谢谢你。 :)
【解决方案2】:

存储库绑定到数据库结构。

服务与您需要的业务逻辑相关。

例如,如果您的事物属于相同的业务逻辑,则 UserService 可以包含获取团队或用户的方法。

【讨论】:

  • 但是这样我就失去了 UserService 控制如何保存/更新/... UserRepository 中的用户的想法,因为我将拥有来自 TeamService 的其他 UserRepository 访问权限。
  • 服务不是 CRUD 的记住每一层的责任。存储库、持久化和检索数据。服务是业务逻辑。想象一个名为 createUser() 的业务方法,但也可以是 getAllUsersFromTeam(teamName)。这很大程度上取决于你把限制放在哪里。但是,正如您所说,服务只有保存/更新/...的概念只会使您将逻辑推入下一层。这不是一个好主意。
  • 是的,服务不仅是 CRUD,但我仍然觉得我不应该在 UserService 之外公开存储库。
  • 您不需要暴露在 UserService 之外,但请记住一般规则,存储库连接到服务而不是其他层,服务调用存储库,而不是其他服务。
  • 这不是我被教导的。服务通过调用在不同实体/域对象上定义业务逻辑的其他服务来形成业务逻辑
猜你喜欢
  • 2021-12-07
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 1970-01-01
  • 1970-01-01
  • 2017-03-21
  • 2019-09-28
  • 2015-05-29
相关资源
最近更新 更多