我目前正在构建CQS风格的DDD应用程序。我对所有组件如何'有一些疑问。互相合作。
但首先,我将简要介绍一下应用程序的结构:
ApplicationService
-> Receives command objects
-> doesn't return any results
-> Acts on Domain model
-> Speaks with Aggregate repository for domain modifications
QueryService
-> Bypasses domain model; doesn't speak with Aggregate Repositories
-> Executes queries against database to populate view
-> Returns 'Representation' objects
REST Controller
-> Receives HTTP requests and binds 'body content' & request params to Command objects
-> delegates to ApplicationService for POST, PUT & DELETE requests
-> Always returns at least some HTTP code
-> delegates to QueryService for GET requests
Infrastructure
-> Handles persistence to DB
-> Contains some scheduling operations
-> Handles foreign domain events our domain model is 'interested' in
'Open Host'
-> This is mainly a Facade to be used by other domains
-> Facade delegates methods to ApplicationService for domain modifications and to QueryService for data retrieval (bypassing Repositories)
我的问题:
DomainEventHandler
与Repository
对应并调用Aggregate
上的某些方法是否可以?或者它应该始终与ApplicationService
?QueryService
返回' Representation
'对象。这些由UI和'Open Host' Facade
用作返回值。可以通过Facade
将这些对象重用为返回值吗?或者Facade
应该创建自己的对象,即使结果基本相同?ApplicationService
需要Commands
'作为输入参数。这些Commands
是否也被Open Host Facade
使用了?或者Facade
是否只接受原始值并在委派给Commands
时将其转换为ApplicationService
?DomainEventHandlers
似乎居住在' Infrastructure
'层。 ApplicationService
或Domain Service
是否也可以订阅Domain Event
?或者这总是Infrastructure
责任?非常欢迎所有建议!
答案 0 :(得分:2)
DomainEventHandler是否可以与Repository对应并在Aggregate上调用某些方法?或者它应该始终与ApplicationService对应吗?
根据我的经验,任何处理程序都是应用程序服务。
QueryService返回' Representation'对象。它们由UI和“开放主机”使用。门面作为返回值。这些对象可以被Facade重用为返回值吗?或者Facade应该创建自己的对象,甚至结果基本相同?
有关开放主机服务和应用服务之间差异的讨论here的批次。我不清楚谁会使用Open Host服务,或者为什么它存在。
ApplicationService需要'命令'作为输入参数。这些命令是否也可以被Open Host Facade使用?或者Facade是否只接受原始值并在委托给ApplicationService时将它们转换为命令?
我会在应用程序的边缘传递原语并将它们转换为命令,然后在Application Services中处理
DomainEventHandlers似乎驻留在' Infrastructure'层。 ApplicationService或Domain Service是否也可以订阅域事件?或者这始终是基础设施的责任吗?
我一直认为我的处理程序是应用程序服务 - 负责编排用户案例的事情。因此,用例可能是"当收到EventX时,发送电子邮件并更新数据库"。在这个例子中,您可能会考虑发送电子邮件的代码"和#34;保存到数据库的代码"是基础设施关注点,但处理程序本身不会。
public class ExampleHandler : IHandle<ExampleEvent>
{
private IRepository _repo;
private ISendEmails _emailer;
public ExampleHandler(Repository repo, ISendEmails emailer)
{
.... set the private fields..
}
public void When(ExampleEvent event)
{
_emailer.Send(event.whatever);
_repo.Save(something);
}
}
说实话,我并不是真的从层面思考 - 我更喜欢六角形的建筑风格。在上面的示例中,事件处理程序只会将依赖项注入其中,然后进行业务处理。