理解DDD(服务、聚合、实体、存储库和规范)

本文关键字:存储 实体 DDD 服务 聚合 理解 | 更新日期: 2023-09-27 18:10:43

我从DDD开始,并试图在我当前的项目中应用,但是正如你可以想象的那样,我有成千上万的问题。

这里我提供了一个示例域,所以我可以提出不同的问题,并作为一个练习,你可以向我解释如何制作东西。


我们假设的系统必须控制公司和每个公司的工作人员。

  • 公司(id、名称、地址)
  • 员工(id、姓名、姓氏、年龄)

一个人只能在一家公司工作,而一家公司可以有很多员工。

操作

系统必须允许向公司添加新员工。为此,它接收公司id和新员工的name, surname, age。有一些限制需要满足:

  • 公司内不允许有相同name, surname and age的员工
  • 员工可以在其他公司工作。

问题

我脑子里一片混乱:)

要实现我正在考虑的操作:

  • 服务接收所有参数。
  • 业务调用CompanyRepository->findCompanyById检索公司实例。
  • Service使用指定的参数创建Employee的新实例。
  • Services调用company->addEmployee将员工附加到公司。
  • company->AddEmployee内检查新员工是否满足条件(规范)。
  • Service调用CompanyRepository->save(company)来持久化公司和员工。

因为company+employee是作为集群(聚合)管理的,所以我认为公司是聚合根。

  1. 这是一个很好的实现吗?
  2. 如果我考虑company+employee是一个聚合,就像我描述的保存集群company+employe的方式一样,当我从存储库中检索公司实例时,我是否也必须检索所有相关的员工?
  3. 尊重规范我可以很容易地理解如何检查,例如,如果一个员工的名字超过10个字符,但是:如果公司有数千名员工,如何检查该员工是否存在于同一家公司?
  4. 规范可以调用存储库操作吗?如果是,考虑到公司+员工集群是正确的,那么什么地方是正确的呢?CustomerRepository->findEmployeeByName(idCompany, nameEmployee)或者最好创建一个特定的EmployeeRepository

理解DDD(服务、聚合、实体、存储库和规范)

1

坏只是一个意见。DDD不应该是教条,你可以充分利用它和你自己的补充来构建好的软件架构。

<标题> 2 h1> ,公司可以惰性加载员工(即,当运行时访问Employee属性后,公司已经检索)或公司可以实现一个Load方法,它也支持分页加载只需要的员工。 <标题> 3

您应该在存储库级别(例如ICompanyRepository.ContainsEmployee(Employee))实现它,并使用底层数据映射器来执行这个繁重的操作。

另外,我倾向于将规范称为存储库中的前置/后置条件,因为这是确保在所有情况下都能实现规范的唯一方法。

<标题> 4

我会避免它,但如果你想确保很多领域规则,你需要在规范中使用它们。顺便说一句,我不会使用存储库,但我会使用服务。

正确的位置取决于需求。如果您想要执行检查以确保域对象以有效状态存储在存储库中,我发现如果您想从ICompanyRepository.AddICompanyRepository.UpdateICompanyRepository.AddOrUpdate中调用规范没有问题。这里的要点是,不应该在对象状态被存储在存储库中和被检索时都验证对象状态。如果您的规范和代码是可靠的,如果存储库已经过滤了域对象并将它们存储在底层数据存储中,那么您可以确定读取操作将获得有效的域对象。

边注:虽然您不应该基于底层数据存储(无论是关系、NoSQL、文件系统…)对域进行建模,但您也不应该像教条一样应用DDD。如果底层数据存储提供了更好的方法来定义数据约束,我将尝试使用它们,而不是实现可能需要访问数据的复杂规范。

您的解决方案应该是最优软件架构和运行时性能之间的平衡。