领域驱动设计和文件存储

Domain driven design and file storage

我正在开发一个允许用户将电影从一个位置复制到他们的用户帐户的应用程序。为此,需要将电影复制到用户的个人文件夹。

我面临的问题是,何时 实际复制文件。目前,我有一个 MovieFactory,在创建后,在工厂方法完成复制后立即将其放入 MovieRepository 中。这似乎工作正常。

但是,存储库和工厂不必相互了解。理想情况下我会这样做:

var movie = this.MovieFactory.CreateFromFile(new FileInfo("MyPhoto.mp4"));
this.MovieRepository.Add(movie);

现在我的想法是在 Add 方法中进行复制,因为您基本上是在复制到存储库本身。但是,这样一来,影片的文件位置也会发生变化。因此,Add 方法必须修改 movie 或 return 一个新的但不同的电影实例。这对我来说听起来像是代码味道,我完全陷入了这种情况。

在说话的时候,文件位置没有被存储。相反,该位置是使用 MovieFileLocator 服务从多个其他电影属性中推断出来的。

所以位置取决于电影的几个属性。你想移动电影,意思是你想修改电影的属性。我想你应该复制一下。像 MovieRepository.Add(电影); movie.LocationProperty=Locations.NewLocation(在这里您将执行文件的实际移动)

您有两个位于应用程序层中的对象。如果我理解正确,复制意味着将电影分配给用户的域逻辑。

在那种情况下,您应该为接受电影和用户的进程创建域服务。这个域服务应该注入一个对象,该对象具有用于处理电影操作的接口并调用类似 movie.assignTo(user.id) 的东西。通过这种方式,您可以明确地揭示分配并将域逻辑与基础结构逻辑分开。

由于问题有DDD标签,我会用更多DDD术语回答:

  • 您使用工厂 CreateFromFile 方法创建了一个 Movie 聚合
  • 在此工厂方法中,您肯定会调用 Movie
  • 的一些构造函数 and/or 方法
  • 您可以发送一个 域事件 MovieCreatedFromFile 并在处理程序中执行任何您想执行的操作(将文件复制到用户的文件夹)
  • 您通过将聚合添加到存储库来继续应用程序服务方法流程

域事件调度和处理的具体工作方式 - 由您决定。由于这是与基础设施相关的工作,我会将其分派到当前工作单元之外。您可以为此使用 Hangfire 之类的轻量级内容。通过这种方式,您可以确保您的聚合是事务边界,但准备好在(不太可能)发生时处理文件复制错误。此 "preparation" 可能只包括通知和手动工作,因为它可能永远不会发生。