我不确定是否要为此使用服务。
据我了解,DDD 的原则之一(我目前正在阅读)是域对象被组织成聚合,并且当您创建聚合根的实例时,它只能直接处理 Aggregate 中的对象(以帮助保持清晰的责任感)。
创建聚合应强制执行任何不变量等。
以客户类为例,客户可能是聚合根,聚合中的另一个类可能是地址。
现在,如果您想创建一个新客户,您应该能够使用客户构造函数或工厂来执行此操作。这样做应该返回一个在聚合边界内功能齐全的对象(因此它不能处理产品,因为它们不是聚合的一部分,但它可以处理地址)。
数据库是次要关注点,仅在将聚合持久化到数据库或从数据库中检索它时发挥作用。
为避免直接与数据库交互,您可以创建一个 Repository 接口(如所讨论的),该接口给定 Customer 实例(包括对 Address 的引用)应该能够将 Aggregate 持久化到数据库中。
关键是存储库接口是您的域模型/层的一部分(存储库的实现不是)。另一个因素是存储库可能最终应该调用相同的“创建”方法,就像您正在创建一个新对象一样(以维护不变量等)。如果您使用的是构造函数,这很简单,因为无论如何,当存储库从数据“创建”对象时,您最终都会调用构造函数。
应用层可以直接与域通信(包括repository接口)。
所以如果你想创建一个对象的新实例,你可以例如
Customer customer = new Customer();
如果应用需要从存储库中检索客户的实例,我想不出它不调用的特殊原因...
Customer customer = _custRepository.GetById(1)
或者...
Customer customer = _custRepository.GetByKey("AlanSmith1")
最终它将得到一个 Customer 对象的实例,该实例在它自己的限制和规则内运行,就像它直接创建新的 Customer 对象一样。
我认为服务应该保留在您尝试使用的“事物”不是对象时。大多数规则(约束等)都可以作为域对象本身的一部分编写。
我正在阅读的 DDD Quickly pdf 就是一个很好的例子。在那里,它们对 Bookshelf 对象有一个约束,因此您只能添加书架可以包含的书籍。
对 BookShelf 对象调用 AddBook 方法会在将书添加到 BookShelf 的 Book 对象集合之前检查是否有可用空间。一个简单的示例,但业务规则由域对象本身强制执行。
顺便说一句,我并不是说以上任何一个都是正确的!目前我正在努力解决所有这些问题!