在将实际逻辑放入DDD域层时遇到麻烦 [英] Having trouble putting real-world logic into the DDD domain layer

查看:64
本文介绍了在将实际逻辑放入DDD域层时遇到麻烦的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尽管对域驱动设计进行了很长时间的研究,但我仍然会发现一些基本知识。

Despite having studied Domain Driven Design for a long time now there are still some basics that I simply figure out.

似乎每次我尝试设计丰富的域层时,我仍然需要很多 Domain Services 或较厚的 Application Layer ,最后我得到了一堆近乎贫乏的领域实体,其中没有真正的逻辑它们,除了 GetTotalAmount之类。关键问题是实体不了解外部事物,并且不宜将任何东西注入到实体中。

It seems that every time I try to design a rich domain layer, I still need a lot of Domain Services or a thick Application Layer, and I end up with a bunch of near-anemic domain entities with no real logic in them, apart from "GetTotalAmount" and the like. The key issue is that entities aren't aware of external stuff, and it's bad practice to inject anything into entities.

让我举一些例子:

1。用户注册服务。用户保留在数据库中,生成并保存文件(用户帐户需要),并发送确认电子邮件。

示例确认电子邮件已在其他主题中进行了广泛讨论,但没有真正的结论。有人建议将逻辑放在应用程序服务中,该服务将获得 EmailService FileService 是从基础结构层注入的。但是,那么我将在域之外使用业务逻辑,对吗?其他人建议创建一个域服务来获取注入的基础结构服务-但在这种情况下,我需要使用接口域层 IEmailService 域层中的基础结构服务 IFileService )也不太好(因为域层无法引用基础架构层)。其他建议建议实施 Udi Dahan的域事件,然后让EmailService和FileService订阅这些事件。但这似乎是一个非常宽松的实现-如果服务失败,会发生什么?请让我知道您认为合适的解决方案在这里。

The example with the confirmation email has been discussed heavily in other threads, but with no real conclusion. Some suggest putting the logic in an application service that gets an EmailService and FileService injected from the infrastructure layer. But then I would have business logic outside of the domain, right? Others suggest creating a domain service that gets the infrastructure services injected - but in that case I would need to have the interfaces of the infrastructure services inside the domain layer (IEmailService and IFileService) which doesn't look too good either (because the domain layer cannot reference the infrastructure layer). And others suggest implementing Udi Dahan's Domain Events and then having the EmailService and FileService subscribe to those events. But that seems like a very loose implementation - and what happens if the services fail? Please let me know what you think is the right solution here.

2。歌曲是从数字音乐商店购买的。购物车已清空。购买被持久化。付款服务被调用。发送电子邮件确认。

好吧,这可能与第一个示例有关。这里的问题是,谁负责协调此事务​​?当然,我可以使用注入的服务将所有内容放入MVC控制器中。但是,如果我要使用真正的DDD,则所有业务逻辑都应在域中。但是,哪个实体应具有购买方法? Song.Purchase() Order.Purchase() OrderProcessor.Purchase()(域服务)? ShoppingCartService.Purchase()(应用程序服务?)

Ok, this might be related to the first example. The question here is, who is responsible for orchestrating this transaction? Of course I could put everything in the MVC controller with injected services. But if I want real DDD all business logic should be in the domain. But which entity should have the "Purchase" method? Song.Purchase()? Order.Purchase()? OrderProcessor.Purchase() (domain service)? ShoppingCartService.Purchase() (application service?)

在这种情况下,我认为很难使用域实体内部的真实业务逻辑。如果不是在实体中注入任何东西的好习惯,那么除了检查其自身(及其聚合状态)之外,他们还能做些其他事情吗?

This is a case where I think it's very hard to use real business logic inside the domain entities. If it's not good practice to inject anything into the entities, how can they ever do other stuff than checking its own (and its aggregate's) state?

我希望这些例子足够清楚,以显示我正在处理的问题。

I hope these examples are clear enough to show the issues I'm dealing with.

推荐答案


用户注册了一项服务。用户被保留在
数据库中,生成并保存文件(用户帐户需要),
并发送确认电子邮件。

A user signs up for a service. The user is persisted in the database, a file is generated and saved (needed for the user account), and a confirmation email is sent.

您可以在此处应用依赖反转原理 。定义这样的域接口:

You can apply Dependency Inversion Principle here. Define a domain interface like this:

void ICanSendConfirmationEmail(EmailAddress address, ...)

void ICanNotifyUserOfSuccessfulRegistration(EmailAddress address, ...)

接口可以被其他域类使用。使用真实的SMTP类在基础结构层中实现此接口。在应用程序启动时注入此实现。这样,您就在域代码中陈述了业务意图,并且域逻辑没有直接引用SMTP基础结构。此处的关键是接口的名称,它应该基于无所不在的语言。

Interface can be used by other domain classes. Implement this interface in infrastructure layer, using real SMTP classes. Inject this implementation on application startup. This way you stated business intent in domain code and your domain logic does not have direct reference to SMTP infrastructure. The key here is the name of the interface, it should be based on Ubiquitous Language.


歌曲是从数字音乐商店购买的。购物车
已清空。购买被持久化。付款服务被调用。
已发送电子邮件确认。好的,这可能与第一个示例有关。这里的问题是,谁负责协调此事务​​?

A song is purchased from a digital music store. The shopping cart is emptied. The purchase is persisted. The payment service is called. An email confirmation is sent. Ok, this might be related to the first example. The question here is, who is responsible for orchestrating this transaction?

使用OOP最佳实践来分配职责(GRASP和SOLID)。单元测试和重构将为您提供设计反馈。编排本身可以是 thin 应用层的一部分。来自 DDD分层体系结构

Use OOP best practices to assign responsibilities (GRASP and SOLID). Unit testing and refactoring will give you a design feedback. Orchestration itself can be part of thin Application Layer. From DDD Layered Architecture:


应用层:定义软件应该执行的工作,并指导
表达域对象解决问题。
层负责的任务对业务有意义,或者对于
与其他系统的应用程序层交互是必需的。

Application Layer: Defines the jobs the software is supposed to do and directs the expressive domain objects to work out problems. The tasks this layer is responsible for are meaningful to the business or necessary for interaction with the application layers of other systems.

保持瘦弱。它不包含业务规则或
知识,而仅协调任务并将委托工作委托给下一层中的
域对象协作。它的
状态不能反映业务情况,但是它的状态
可以反映用户或程序的任务进度。

This layer is kept thin. It does not contain business rules or knowledge, but only coordinates tasks and delegates work to collaborations of domain objects in the next layer down. It does not have state reflecting the business situation, but it can have state that reflects the progress of a task for the user or the program.

这篇关于在将实际逻辑放入DDD域层时遇到麻烦的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆