TLDR;滚动到底部寻找答案,但背景故事会提供一些很好的背景。
如果您域的调用者必须知道调用事物的顺序,那么您就错过了在您的域中封装业务逻辑的机会,这是anemic domain 的症状。
@RobertBräutigam 提出了一个非常好的观点:
要求一系列技术调用是一种时间耦合形式,它被认为是一种不好的做法,并且与 DDD 没有直接关系。
确实如此,但是当您使用域模型执行此操作时,情况会更糟,因为非域关注点与域关注点混合在一起。意图在非业务逻辑的海洋中迷失了。如果可以的话,您可以寻找一个封装了排序的高阶aggregate。借用 Robert 的例子,与其先预订航班,再预订酒店房间,然后将其强加给客户端,您可以让 Vacation 聚合同时接受并验证它。
我知道在你的情况下这听起来错误,我怀疑你是对的。有一个明确的依赖关系,不可能同时发生,所以我们不能成为故事的结局。当您对必须在“最终”状态之前发生的中间事务有明确的依赖关系时,我们就有……编排(想想 saga、分布式事务、域事件和所有这些优点)。
您对文件操作的描述跨越了事务。域的操作(状态更改)在分布式事务中的每个点都是事务性的,但总体上不是事务性的。所以当@choquero70 说
您所描述的是域模型操作的编排。这就是应用层的工作,是领域模型之上的一层。
这也是正确的。编排是关键。每个步骤都必须操作域的状态一次,并且只操作一次,并使其处于有效状态,但可以有多个步骤。
时间轴上的每个单独点都是您的域状态中的有效时刻。
那么,回到你的模型。如果您公开一个接口,其中包含对 all 步骤的多个可能调用,那么您会让自己对被乱序调用的事情保持开放态度。让这不可能或至少不可能。编排不仅仅是要做什么,而是要防止发生什么。创建更小的接口/类以避免意外增加可能被误用的“表面积”。
通过这种方式,您可以通过向调用者提供有效的中间状态来指导调用者下一步该做什么。但是,这是重要的部分,以什么顺序调用什么的负担不在调用者身上。当然,调用者可以知道该做什么,但为什么要强迫它。
你的基本算法是一样的:上传、转换、下载。
调用者有责任以正确的顺序调用方法吗?
不完全是。调用者有责任根据您的域的状态从合法选项中进行选择。通过业务方法在适合调用者使用的正确建模的 moment/interval 聚合上呈现这些选择是“您的”责任。
或者我们是否让方法在它自己的逻辑之前处理依赖操作?
如果您已正确设置编排,则无需执行此操作。但无论如何验证确实有意义。
附带说明,您所做的编排的每个步骤本质上都应该是非常线性的。我告诉我的开发人员要怀疑其中包含 if 语句的编排步骤。如果存在 if,则最好成为另一个编排步骤的一部分或封装在业务逻辑中。