这听起来不像 DDD
您的问题中没有太多关于您的域模型的内容。您提到了“将员工添加到系统和 Salesforce”,但除此之外,我对您的应用程序在商业意义上的用途没有真正的了解。我对“员工”和“销售人员”的理解是基于对这些词的熟悉程度,而不是基于它们在您的系统中的模型的解释。
我真的不知道“订单应用程序服务”在您的模型中应该代表什么。我收到“订单”和“订单通知”。似乎“客户”下达了“订单”,一些“订阅者”得到了“通知”,但其中很多都是基于我对设计模式的先验知识。
您应该能够描述业务域模型,因为如果计算机不存在,它会起作用。 如果你需要一个计算机术语来解释这个想法,它可能混入了模型之外的东西。
显然,您需要将应用程序逻辑与您的域逻辑集成,但这不应该混淆您的关注点。但是,有一些方法可以解决这个问题。
你怎么能解决它
- 您可以使用接口而不是实现特定的类来对领域层中的服务进行建模。这就是所谓的界面隔离原则。有道理的是,您的模型的一部分包括在客户下订单时通知负责的员工。但是,不一定有任何理由将此通知的实现与其建模目的相结合。可能有主管在拥挤的办公室中通过对讲机发布公告,或者可能有一封电子邮件由自动化系统发送。这两个示例都服务于相同的业务目的。
IOrderNotificationService
您可以拥有一个只包含一个方法的接口,而不是在您的域层中嵌入电子邮件服务void NotifyOrderReceived(Order order);
. 这样,您就可以在域层中拥有所需的所有业务逻辑,而不会引入不必要的问题,例如“电子邮件”实现或数据库的持久性。我猜是这样,但是您的OrderNotificationService
和OrderApplicationService
确实是对同一事件的响应,但是一个具有数据库依赖关系,另一个具有 SMTP 依赖关系。两者都是基础设施问题。
在许多情况下,针对单个接口进行编码就足够了。但是,存在一个问题,即您的域对象现在依赖于注入的服务或全局变量。此外,这可能表明这些实体对它们的依赖关系了解太多。客户可能不需要知道如何处理订单的内部工作原理,而只需要知道它已被处理并且他们将收到他们所订购的东西。同样,员工可能不会将自己添加到 Salesforce,因为他在成为员工之前并不知道这件事。他只知道他刚刚找到工作。
这个问题有一个很好的解决方案...
您可以使用“域事件”模式。基本思想是域对象只知道刚刚发生了什么以及它们的状态是如何改变的,而不需要知道关于保持或传播改变的状态的任何事情。他们处理其内部逻辑,然后引发“领域事件”。这更类似于客户下订单然后大喊“哟,我订购了这个产品!” 或者一名员工被录用,然后大喊:“哟,我找到了工作!”。采用这种方法将大大简化您的域逻辑,并允许您实现更清晰的关注点分离。Udi Dahan 有一系列优秀的博客文章,他在其中解释了利用领域事件模式背后的逻辑,并提供了一个非常简单但非常有效的实现。以下是一些链接:
现在,如果您是那种喜欢在完全理解代码之前复制和粘贴代码的开发人员,我建议您从这些帖子中的第三篇开始。他们记录了 Udi Dahan 对这种模式的思考和经验的演变。最健全的代码示例出现在第三篇文章中。理想情况下,您应该按顺序阅读所有三本书,这样您就可以遵循他的逻辑并真正理解您如何从他的方法中受益,以及为什么它准确地代表了“领域驱动设计”。
作为对“领域事件模式”的补充说明,Eric Evans 在 2009 年回顾了他自撰写开创性著作以来对领域驱动设计的了解,指出领域事件是他书中被严重忽视的核心构建块。他的演讲摘要可在此处获得,演示文稿的链接可在此处获得。
其他一些可能帮助您成功应用此模式的资源包括 Jimmy Bogard 的文章加强您的领域:领域事件和Martin Fowler 的领域事件文章。Bogard 从引用的链接中提供了指向其他有用的 DDD 博客文章的链接。
一般来说,
如果您真的想尝试应用领域驱动设计,那么通过真正了解您正在建模的内容以及您为什么目的实施的内容,您将获得更大的成功。简单地使用您不熟悉的术语并将您的代码标记为这样并没有隐含的价值。DDD 可能非常有用,但是如果您不花时间理解为什么要进行区分和设计决策,您最终会遇到很多不必要的抽象和一般的混乱。