领域驱动的设计理念

时间:2012-09-07 17:27:14

标签: oop architecture domain-driven-design separation-of-concerns object-oriented-analysis

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

我有以下几层:

  • 应用
  • 基础设施

所以,我们假设我有以下类:

  • Order
  • EmailService
  • OrderNotificationService
  • OrderApplicationService

显然,Order进入域层,OrderApplicationService进入应用层。 EmailService是用于发送电子邮件的通用服务,并在基础架构层中实现。 OrderNotificationService是发送订单通知的特定实现。 OrderNotificationService使用EmailService发送实际的电子邮件。

所以,我的第一个问题是:OrderNotificationService是否可以实现为域服务,应用服务或基础架构服务?

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

  • Employee
  • SalesforceService

假设当员工加入系统时,他们也应该被添加到Salesforce。 SalesforceService是使用Salesforce api注册用户的服务。 SalesforceService是否可以通过发送员工信息实现为应用服务将使用的域服务或通用基础结构服务?

感谢您的建议。

2 个答案:

答案 0 :(得分:11)

这听起来不像DDD

您的问题中没有多少内容涉及您的域模型。您提到了一个"员工被添加到系统和Salesforce",但除此之外我还没有真正意识到您的应用程序打算做什么,在商业意义上。我对"员工的理解"和#34; Salesforce"基于对单词的熟悉程度,而不是基于他们的模型在系统中的解释。

我真的不知道"订单申请服务"应该用你的模型来表示。我得到了一个"订单"和"订单通知"。它似乎是一个"客户"制作一个" Order"和一些" Subscriber"得到"通知",但其中很多是基于我之前对设计模式的了解。

您应该能够描述业务领域模型,因为如果计算机不存在,它将起作用。如果您需要一个计算机术语来解释这个想法,它可能会混合某些东西这是模特的外在因素。

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

如何解决问题

  1. 您可以使用接口而不是特定于实现的类来为域层中的服务建模。这被称为interface segregation principle。有意义的是,您的模型的一部分包括在客户下订单时通知负责的员工。但是,没有必要将此通知的实施与其建模目的相结合。可能有主管在拥挤的办公室中通过对讲机发布通知,或者可能有自动系统发送的电子邮件。这两个示例都用于相同的业务目的。您可以拥有一个只包含方法IOrderNotificationService的{​​{1}}界面,而不是在您的域图层中嵌入电子邮件服务。这样,您就可以在域层中获得所需的所有业务逻辑,而不会引入不必要的问题,例如" Email"数据库的实现或持久性。我猜这个,但你的void NotifyOrderReceived(Order order);OrderNotificationService实际上是对同一事件的响应,但是一个具有数据库依赖性而另一个具有SMTP依赖性。两者都是基础设施问题
  2. 在许多情况下,针对单个接口进行编码就足够了。但是,存在一个问题,即您的域对象现在依赖于注入的服务或全局变量。此外,这可能表明这些实体对其依赖性了解太多。客户可能不需要知道订单如何处理的内部工作方式,而只需知道订单处理完毕并且他们将收到他们订购的订单。同样,员工可能不会将自己添加到Salesforce,因为他在成为员工之前并不了解它。他所知道的只是他找到了一份工作。

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

    1. 您可以使用"域事件"图案。基本思想是域对象只知道刚刚发生了什么以及状态如何改变,但是不需要知道任何关于持久化或传播改变状态的信息。他们处理内部逻辑,然后提出一个"域事件"。这更类似于客户下订单然后大喊大叫哟,我订购了这个产品!"或雇员被雇用然后大喊大叫,哟,我找到了工作!"。采用这种方法将大大简化您的域逻辑,并使您能够更清晰地分离关注点。 Udi Dahan有一系列精彩的博客文章,他解释了利用域事件模式背后的逻辑,并提供了一个非常简单但非常有效的实现。以下是一些链接:

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

      作为"域事件模式"的补充理由,Eric Evans' 2009年回顾他从领域驱动设计中学到的东西,因为他写了一本开创性的书,指出 Domain Events在他的书中是一个被忽视的核心构件。他的演讲摘要可以here,并且演示文稿的链接可用here

      可能有助于您成功应用此模式的其他一些资源包括Jimmy Bogard的文章Strengthening your Domain: Domain EventsMartin Fowler's Domain Event article。 Bogard从引用的链接中链接到其他有用的DDD博客帖子。

      一般来说,

      如果您真的想尝试应用域驱动设计,那么通过真正了解您的建模内容以及为实现目的而实施的内容,您将会更加成功。简单地使用您不熟悉的术语并标记代码就没有任何隐含的价值。 DDD可以提供非常有用的帮助,但是如果你没有花时间去理解为什么要做出区分和设计决定,你最终会得到很多不必要的抽象和一般的混淆。

答案 1 :(得分:1)

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

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

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