似乎每次我尝试设计一个丰富的域层时,我仍然需要很多域名服务或一个厚实的应用层,而且我最终会出现一堆没有真实逻辑的近似贫乏的域实体,除了“GetTotalAmount”等。关键的问题是实体不知道外部的东西,而且对实体注入任何东西都是不好的做法。
让我举一些例子:
用户注册服务。用户被保存在数据库中,生成并保存文件(用户帐户需要),并发送确认电子邮件。
具有确认电子邮件的例子已经在其他主题中进行了大量讨论,但没有得到真正的结论。有些建议将逻辑放在应用程序服务中,从基础结构层注入一个EmailService和FileService。但是,那么我会在域外有业务逻辑吗?其他人建议创建一个可以注入基础架构服务的域服务,但是在这种情况下,我需要在域层(IEmailService和IFileService)内部具有基础设施服务的接口,这不是太好(因为域层无法参考基础设施层)。而其他人建议实施Udi Dahan’s Domain Events,然后让EmailService和FileService订阅这些事件。但这似乎是一个非常宽松的实现 – 如果服务失败会发生什么?请让我知道你认为这是正确的解决方案。
一首歌从数字音乐商店购买。购物车已清空。购买持续存在。付款服务被称为。发送电子邮件确认。
好的,这可能与第一个例子有关。这里的问题是谁负责协调交易?当然,我可以把所有的东西放在MVC控制器中,注入服务。但是如果我想要真正的DDD,所有的业务逻辑都应该在域中。但哪个实体应该有“购买”方式? Song.Purchase()? Order.Purchase()? OrderProcessor.Purchase()(域服务)? ShoppingCartService.Purchase()(应用服务?)
这是一个我认为在域实体中使用真实业务逻辑很困难的情况。如果注入任何东西不是很好的做法,那么他们怎样才能做其他的事情,而不是检查自己的(和它的聚合)的状态?
我希望这些例子足以显示我正在处理的问题。
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.
您可以在这里申请Dependency Inversion Principle。定义一个域接口,如下所示:
void ICanSendConfirmationEmail(EmailAddress address,...)
要么
void ICanNotifyUserOfSuccessfulRegistration(EmailAddress address,...)
接口可以被其他域类使用。在基础架构层实现此接口,使用真正的SMTP类。在应用程序启动时注入此实现。通过这种方式,您在域代码中表示业务意图,您的域逻辑不直接引用SMTP基础架构。这里的关键是接口的名称,它应该基于无所不在的语言。
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)。单元测试和重构将给您一个设计反馈。编排本身可以是薄应用层的一部分。从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.