3

我在使用域驱动设计构建的应用程序中遇到了一些概念问题。

我有以下几层:

  • 应用
  • 领域
  • 基础设施

所以,假设我有以下课程:

  • Order
  • EmailService
  • OrderNotificationService
  • OrderApplicationService

很明显,Order领域层和OrderApplicationService应用层都有。这EmailService是用于发送电子邮件的通用服务,并在基础设施层中实现。这OrderNotificationService是发送订单通知的具体实现。使用发送实际的电子邮件 OrderNotificationServiceEmailService

所以,我的第一个问题是:会OrderNotificationService被实现为域服务、应用程序服务还是基础设施服务?

对于我的下一个问题,让我们假设以下对象:

  • Employee
  • SalesforceService

假设当员工被添加到系统时,他们也应该被添加到 Salesforce。这SalesforceService是一项使用 Salesforce api 注册用户的服务。将SalesforceService被实现为应用程序服务通过发送员工信息使用的域服务或通用基础设施服务吗?

感谢您的建议。

4

2 回答 2

11

这听起来不像 DDD

您的问题中没有太多关于您的域模型的内容。您提到了“将员工添加到系统和 Salesforce”,但除此之外,我对您的应用程序在商业意义上的用途没有真正的了解。我对“员工”和“销售人员”的理解是基于对这些词的熟悉程度,而不是基于它们在您的系统中的模型的解释。

我真的不知道“订单应用程序服务”在您的模型中应该代表什么。我收到“订单”和“订单通知”。似乎“客户”下达了“订单”,一些“订阅者”得到了“通知”,但其中很多都是基于我对设计模式的先验知识。

您应该能够描述业务域模型,因为如果计算机不存在,它会起作用。 如果你需要一个计算机术语来解释这个想法,它可能混入了模型之外的东西。

显然,您需要将应用程序逻辑与您的域逻辑集成,但这不应该混淆您的关注点。但是,有一些方法可以解决这个问题。

你怎么能解决它

  1. 您可以使用接口而不是实现特定的类来对领域层中的服务进行建模。这就是所谓的界面隔离原则。有道理的是,您的模型的一部分包括在客户下订单时通知负责的员工。但是,不一定有任何理由将此通知的实现与其建模目的相结合。可能有主管在拥挤的办公室中通过对讲机发布公告,或者可能有一封电子邮件由自动化系统发送。这两个示例都服务于相同的业务目的。IOrderNotificationService您可以拥有一个只包含一个方法的接口,而不是在您的域层中嵌入电子邮件服务void NotifyOrderReceived(Order order);. 这样,您就可以在域层中拥有所需的所有业务逻辑,而不会引入不必要的问题,例如“电子邮件”实现或数据库的持久性。我猜是这样,但是您的OrderNotificationServiceOrderApplicationService确实是对同一事件的响应,但是一个具有数据库依赖关系,另一个具有 SMTP 依赖关系。两者都是基础设施问题。

在许多情况下,针对单个接口进行编码就足够了。但是,存在一个问题,即您的域对象现在依赖于注入的服务或全局变量。此外,这可能表明这些实体对它们的依赖关系了解太多。客户可能不需要知道如何处理订单的内部工作原理,而只需要知道它已被处理并且他们将收到他们所订购的东西。同样,员工可能不会将自己添加到 Salesforce,因为他在成为员工之前并不知道这件事。他只知道他刚刚找到工作。

这个问题有一个很好的解决方案...

  1. 您可以使用“域事件”模式。基本思想是域对象只知道刚刚发生了什么以及它们的状态是如何改变的,而不需要知道关于保持或传播改变的状态的任何事情。他们处理其内部逻辑,然后引发“领域事件”。这更类似于客户下订单然后大喊“哟,我订购了这个产品!” 或者一名员工被录用,然后大喊:“哟,我找到了工作!”。采用这种方法将大大简化您的域逻辑,并允许您实现更清晰的关注点分离。Udi Dahan 有一系列优秀的博客文章,他在其中解释了利用领域事件模式背后的逻辑,并提供了一个非常简单但非常有效的实现。以下是一些链接:

现在,如果您是那种喜欢在完全理解代码之前复制和粘贴代码的开发人员,我建议您从这些帖子中的第三篇开始。他们记录了 Udi Dahan 对这种模式的思考和经验的演变。最健全的代码示例出现在第三篇文章中。理想情况下,您应该按顺序阅读所有三本书,这样您就可以遵循他的逻辑并真正理解您如何从他的方法中受益,以及为什么它准确地代表了“领域驱动设计”。

作为对“领域事件模式”的补充说明,Eric Evans 在 2009 年回顾了他自撰写开创性著作以来对领域驱动设计的了解,指出领域事件是他书中被严重忽视的核心构建块。他的演讲摘要可在此处获得,演示文稿的链接可在此处获得。

其他一些可能帮助您成功应用此模式的资源包括 Jimmy Bogard 的文章加强您的领域:领域事件Martin Fowler 的领域事件文章。Bogard 从引用的链接中提供了指向其他有用的 DDD 博客文章的链接。

一般来说,

如果您真的想尝试应用领域驱动设计,那么通过真正了解您正在建模的内容以及您为什么目的实施的内容,您将获得更大的成功。简单地使用您不熟悉的术语并将您的代码标记为这样并没有隐含的价值。DDD 可能非常有用,但是如果您不花时间理解为什么要进行区分和设计决策,您最终会遇到很多不必要的抽象和一般的混乱。

于 2012-09-08T00:09:30.573 回答
1

OrderNotificationService 属于领域层。如果您认为它是 Order 类的协作者,它应该靠近 Order 类。IMO,我认为 OrderNotificationService 可以改为 OrderNotifier ,其职责是在订单状态更改时发布通知。它显然是一个接口而不是一个具体的类。它可以由OrderNotificatoinService实现,属于基础设施层或应用层。无需将 OrderNotificationService 设为接口。

这同样适用于 SalesforceService。将其视为 Employee 类的协作者,负责在创建员工时注册新员工信息。它属于领域层。与前面的情况相同,您可以考虑将其重命名为 EmployeeRegister 或类似的名称,这描述了它的角色而不是它的实现。改为使用 SaleforceService 实现它。

一个副作用是您的域对象(订单/员工)间接依赖于应用程序/基础设施层的类。如果您的域对象由其他域对象实例化,您可能会发现在创建域对象时注入第三方依赖项很棘手。这篇文章可能有用。http://thinkinginobjects.com/2012/09/05/abstract-factory-in-domain-modelling/

于 2012-09-07T22:44:43.810 回答