oop - 域驱动的设计概念

标签 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是通过发送员工信息将其实现为应用程序服务将使用的域服务还是通用基础结构服务?

谢谢你的建议。

最佳答案

这听起来不像DDD

关于您的域模型,您的问题中没有太多内容。您提到了“将雇员添加到系统和Salesforce中”,但除此之外,从业务的角度来看,我对您的应用程序打算做什么没有真正的了解。我对“雇员”和“ Salesforce”的理解是基于对词语的熟悉,而不是基于他们在系统中的模型解释。

对于您的模型,“订购应用程序服务”应该代表什么我真的不了解。我得到一个“订单”和“订单通知”。似乎“客户”发出了“订单”,有些“订户”得到了“通知”,但这很多是基于我对设计模式的先前了解。

您应该能够描述业务域模型,因为如果计算机不存在,它将可以正常工作。如果您需要一个计算机术语来解释这个想法,那么它可能是模型中外在的东西。

显然,您需要将应用程序逻辑与域逻辑集成在一起,但这不会引起您的疑虑。但是,有一些解决方法。

如何解决


您可以使用接口而不是特定于实现的类在域层中对服务进行建模。这称为interface segregation principle。有意义的是,模型的一部分包括当客户下订单时通知负责的员工。但是,此通知的实现并不一定要与其建模目的耦合。在拥挤的办公室中,可能有主管通过对讲机发布通知,或者可能有自动化系统发送的电子邮件。这两个示例都具有相同的业务目的。可以将一个IOrderNotificationService接口简单地包含一个方法void NotifyOrderReceived(Order order);,而不是在域层中嵌入电子邮件服务。这样,您就可以在域层中拥有所需的所有业务逻辑,而不会引起不必要的担忧,例如“电子邮件”实现或数据库的持久性。我正在猜测,但是您的OrderNotificationServiceOrderApplicationService实际上是对同一事件的响应,但是一个具有数据库依赖性,另一个具有SMTP依赖性。两者都是基础设施问题。


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

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


您可以使用“域事件”模式。基本思想是,域对象仅知道刚刚发生的事情以及它们的状态如何更改,而无需了解任何有关持久或传播已更改状态的信息。他们处理内部逻辑,然后引发“域事件”。这更类似于客户下订单然后大声喊“ Yo,我订购了该产品!”。或某个雇员被录用然后大喊:“是的,我找到了工作!”。采用这种方法将大大简化您的域逻辑,并使您可以更清晰地分离关注点。 Udi Dahan撰写了一系列精彩的博客文章,他在其中解释了利用Domain Event模式背后的逻辑,并提供了一个非常简单但非常有效的实现。以下是一些链接:


How to create fully encapsulated Domain Models
Domain Events – Take 2
Domain Events - Salvation



现在,如果您是喜欢在完全理解代码之前复制和粘贴代码的开发人员,那么建议您从这些文章的第三篇开始。他们记录了乌迪·达汉(Udi Dahan)对模式的看法和经验的演变。最合理的代码示例出现在第三篇文章中。理想情况下,您将按顺序阅读所有三个内容,以便您可以遵循他的逻辑并真正理解您如何从他的方法中受益,以及为什么它可以准确地表示“域驱动设计”。

作为“域事件模式”的补充理由,埃里克·埃文斯(Eric Evans)在2009年回顾了自从他撰写开创性著作以来所学到的关于域驱动设计的知识,这表明域事件是他的书中被大大忽略的核心组成部分。 here提供了他的演讲摘要,并且here提供了演示文稿的链接。

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

一般来说,

如果您真的想尝试应用领域驱动的设计,那么您将真正了解您要建模的内容以及为实现什么目的而要实现的内容,将会获得更大的成功。仅使用您不熟悉的术语并以这样的方式标记代码没有任何隐含的价值。 DDD可能会非常有用,但是如果您不花时间去理解为什么要进行区分和设计决策,则会导致很多不必要的抽象和普遍的混乱。

关于oop - 域驱动的设计概念,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12322736/

相关文章:

orm - DDD : the Repository contract

python - 如何按属性访问列表中的对象?

microservices - DDD 中的编排 Sagas - 集成事件链?

domain-driven-design - 领域驱动设计——领域或安全

android - 最佳实践 phonegap 架构

performance - 是否对现代CPU缓存进行了优化以应对不断发展的步伐?跨线程?

c# - 使用 msmq 队列对服务进行负载平衡?

oop - 多重继承是邪恶的吗?

perl - 即使子类覆盖该属性,也会默认使用 Moose 属性

matlab - 您如何在 MATLAB 中从类外部将类属性设置为只读?