3

我是 DDD 的新手。我有一个配置文件类和一个配置文件存储库类。PROFILE 类包含以下字段 -> Id、Description、ImageFilePath

因此,当我添加一个新的配置文件时,我将图像上传到服务器并将其路径存储在我的数据库中。

当我删除配置文件时,图像也应该从我的文件系统中删除。

我的问题:

我在哪里为此添加逻辑。我的配置文件存储库有一个 Delete 方法。我应该在这里添加这个逻辑。或者我应该添加一个服务来封装这两个操作。

任何评论将不胜感激...

谢谢

4

3 回答 3

2

您有两个与图像相关的不同“动作”。你有一个“物理”过程和一个“逻辑”过程。逻辑过程是将有关图像的信息保存到域存储库中,因为它是域的一部分。添加(和删除)的物理过程是逻辑过程的先决条件。

退一步说,物理过程完全独立于逻辑过程,但反之则不然。如果未保存图像,您显然不想保留有关图像的元信息(在域中)。此外,如果您无法删除物理文件,您也不想从域中删除信息。

域应包含从数据源中删除图像的逻辑实例所需的信息。将域视为物理上独立的应用程序。在这种情况下,域实际上并不知道它所保存的数据与物理文件有任何关系。确保保持这种方式。

通常,我将实体放在一个程序集中,然后将我的存储库和域服务放在另一个程序集中。应用程序服务位于域模型之外,但利用它来完成工作。因此应用程序服务使用一个或域服务或其他应用程序服务,并且域服务可以使用一个或多个存储库。

记住这一点,实际删除逻辑有两个地方,第三个地方来协调它们。如果我这样做,这就是它的工作方式。域服务将利用存储库从底层数据源进行逻辑删除(以及您将需要的检索)。除了使用域对象实例之外,它不知道其他任何事情。我还将有一个应用程序服务(域外),专门处理删除物理实例。为了论证起见,我假设您有一个“ImageRepository”类和一个“ImageServices”类,它们分别包含您的域存储库和域服务。您的 ImageServices 需要一个 Delete() 方法,以及您正在使用的任何 Find() 方法。

如果您无法删除物理实例,您不想删除逻辑实例,因此请确保您有一种方法可以衡量物理映像的删除操作是否成功。在这种情况下,我可能会使用某种自定义异常(因为我认为删除文件是通常不会失败的标准操作)。这通常属于“管理”领域。所以通常我有一个名为“ImageManagementService”的应用程序服务。为简单起见,此服务(因为它是应用程序的一部分而不是域的一部分)可以有一个私有方法来执行物理删除。我们称之为“DeleteImageFile()”。

第三个地方是这两个操作的协调,也作为一个应用服务。我只是将其设为“ImageManagementService”中的公共方法。我们可以称它为“RemoveImage”。此应用程序服务将执行以下操作:

  1. 从域服务中检索实例信息(对存储库的直通调用)。
  2. 使用实例信息定位物理文件并将其删除(再次提到的第一个应用程序服务)。
  3. 如果物理删除成功,则删除实例(返回域服务,再次对存储库进行外观处理)。

因此,应用程序本身会从“ImageManagementService”实例调用“RemoveImage()”方法。在内部,“RemoveImage()”首先从域的“ImageServices”中调用“FindBy..()”来从域中获取一个实例。文件路径用于从那里调用“ImageManagementService”实例中的私有“DeleteImageFile() 方法。成功后,它将调用域的“ImageService”中的“Delete()”方法,该方法充当门面到您的存储库。

我认为在这种情况下关注关注点的分离是非常重要的,因为如果你有一个明确的分离(你可以用不同的程序集来做),你会很容易知道哪种逻辑可以放在哪个地方。我强烈推荐埃文的书。此外,为了快速了解与 DDD 相关的 SOC 概念,我建议查看 Jeffrey Palermo 关于“洋葱架构”的三部分系列。

关于为什么要使用域服务而不是直接从应用程序服务调用存储库,请注意几点。首先,存储库具有比域服务更复杂的实例化。请记住,它主要是一个外观,但可能具有不适合域中其他任何地方的附加逻辑。如果您想强制使用唯一的文件名,这可能是一个很好的例子。域对象本身不直接了解其他聚合中的其他域对象,因此域服务可能会在保存操作之前检查具有相同名称的现有实例。非常方便,确实!此外,域服务不限于单个存储库。您可以让域服务协调多个存储库之间的工作。如果您有重叠的聚合,您可能需要同时使用两个相关的聚合根调用工作。您可以在域服务中执行此操作,将这种逻辑保留在域中,而不是渗入应用程序。

希望这可以帮助。我确信还有其他方法可以做到这一点,但这是我在自己的具有类似场景的应用程序中找到成功的方式。

于 2009-09-20T14:31:12.367 回答
1

@joseph.ferris:“通常,我将实体放在一个程序集中,然后将我的存储库和域服务放在另一个程序集中。”

就个人而言,我更喜欢将程序集视为一个部署单元,而不是关注点分离设计工具。为此,我宁愿使用命名空间。

以这种方式确保没有循环依赖(在这些命名空间之间)更加困难,但是像 NDepend 这样的工具可以提供帮助。

于 2009-09-21T07:59:38.397 回答
0

在第一种方法中,我想我会选择最简单的方法,并从 ImageRepository 内的磁盘中删除物理图像。它可能不是最“正确”或“纯粹”的解决方案,但它是最简单的解决方案,这符合“选择最简单有效的解决方案”慢板。

当在项目的后期阶段,你觉得这个解决方案不好,并且你觉得你需要一个更复杂(也许更纯粹)的解决方案,比如 joseph.ferris 提出的那个,那么你总是可以重构它。

重构一个简单的解决方案比重构一个复杂的解决方案更容易。:)

于 2009-09-21T08:07:54.090 回答