【问题标题】:Domain Driven Design - Services should know about other services ? Or should know multiple repositories?领域驱动设计 - 服务应该了解其他服务吗?或者应该知道多个存储库?
【发布时间】:2021-11-14 23:01:47
【问题描述】:

我正在创建一个后端应用程序,并且我正在尝试实施领域驱动设计。 但是,我有一个关于我的数据结构的问题,我打算澄清一下。

数据库结构

Users
Id (PK ????)
First Name
Last Name
Email
Password
Customers Profile
User Id (PK / FK ????)
Height
Weight
Personal Trainers Profile
User Id (PK / FK ????)
Specialties

考虑到上面表示的数据库,我对如何构建我的应用程序的控制器、服务和存储库有一些疑问。

假设我想更新客户资料及其用户:

  • 我调用客户控制器(更新端点)
  • 客户控制器调用客户服务(更新客户方法)
  • 客户服务调用客户存储库来更新客户资料

并在用户表上更新他们各自的用户? 客户服务是否应该从用户服务调用更新方法? 还是客户服务应该直接调用用户存储库?

我很困惑,不知道它是否正确,服务知道其他服务,或者服务知道理论上属于其他服务的存储库。

如果有人可以帮助我澄清我的疑问,我将非常感激????

【问题讨论】:

    标签: javascript node.js express sequelize.js domain-driven-design


    【解决方案1】:

    我认为数据库结构可以改进。

    与其将表格命名为 Customer Profile 和 Personal Trainer Profile,不如将其命名为 Customers 和 Personal Trainers。

    作为 A Customer 是用户 & Personal Trainer 是用户

    更新的数据库结构

    Users
    Id (PK ?)
    First Name
    Last Name
    Email
    Password
    Customers
    Id (PK ?)
    User Id (FK ?)
    Height
    Weight
    Personal Trainers
    Id (PK ?)
    User Id (FK ?)
    Specialties

    总根是客户和私人教练。

    现在控制器和服务将面向客户和私人教练。

    并且对客户的用户表字段的任何更新都将通过客户控制器完成。

    类定义 public class Customers extends Users & public class PersonalTrainers extends Users

    【讨论】:

      【解决方案2】:

      对不起,如果我有点“粗鲁”,但在你的方法中,没有关于 DDD 的真正线索。我的意思是:控制器、服务和存储库是使用 Spring 开发应用程序的“事实”方式。但这并不是真正的 DDD。要使用 DDD 实现它,您必须忘记数据库,专注于域的实体,识别它们的功能并开始考虑如何将其转换为代码。

      通过这个前言,我可以说,在这种“事实”方法中,也可以采用 DDD,但代价是重新考虑生成代码的所有过程。

      因此,在您的模型中,我会这样做:

      • 确定您要建模的域的实体(在这里您必须找到根实体、聚合和值对象 -link 1link 2);
      • 鉴于 DDD 是一种面向对象的方法,一旦您确定了实体(相信我,这并不像看起来那么简单),您需要确定每个实体提供的功能。因此,例如,对于 PersonalTrainer 实体,一个可能的函数可能是 acceptTrainee(Course course, Person trainee),它添加一个新的 Person参加课程(请记住,这是一个示例,我不知道您的域)。

      一旦您了解了您的实体,或者至少您开始识别它们和一些功能,您就可以考虑代码了。在这里,您可以在多种架构之间进行选择:cleanports & adaptersonion、3 层架构(Spring 的默认和经典方法:控制器、服务和带有实体的存储库)。我个人的做法或多或少是here所描述的。

      我建议您搜索并阅读大量有关如何做这些事情的信息。不幸的是,没有灵丹妙药:有时域真的很简单,而 DDD 的额外开销和“不寻常的”架构完全没用;有时域复杂且庞大,因此具有更精细架构的 DDD 方法是更好的选择。

      最后,为了给您一个具体的答案来处理您的案例,在确定实体及其功能之后,我会将您生成的模型放入 domain 包中。在这里,我还将定义 Repository 接口,用于持久化实体(但稍后会实现)。一旦你有了这个,你就可以开发服务,你可以使用你在中拥有的东西把所有的东西放在一起。我会将此代码放入 application 包中(但请记住,这不是法律:如果您认为更好,请将它们放在不同的地方,或者使用不同的名称 - 看看 @987654327 @,我真的很喜欢这种方法)。最后,我将开始实现 infrastructure 层的代码,其中将实现定义到 domainapplication 层的所有接口.这里我还要放 Controllers

      请记住:这种方法只允许单向连接(域 -> 应用程序 -> 基础设施),但不允许反向连接。

      最后,如果您考虑如何使用一些 ORM 框架来管理域实体,我建议您阅读以下链接:domain vs persistence model; stackoverflow question about this; domain and persistence separated.

      【讨论】:

        【解决方案3】:

        聚合是确保聚合内一致性的独立对象。 User 代表一个特定概念,CustomerProfile 代表另一个概念。 CustomerProfile 应该有自己的 ID(不一定是 UserId)。没有什么能阻止您按照自己的方式对其进行建模,但是将两个聚合上的状态更改保持分开会让您的生活变得更轻松。

        话虽如此,每当我确实发现我的应用程序服务以某种方式相互利用时,我都会应用古老的“计算机科学中的所有问题都可以通过另一个层次的间接”。我采用通用位并制作Task 并在每个位中使用它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-24
          • 1970-01-01
          • 2011-03-25
          • 2019-05-03
          • 1970-01-01
          相关资源
          最近更新 更多