从另一个命令 Handle() 方法中调用命令 [英] Calling commands from within another command Handle() method
问题描述
您好,我正在使用 Simple Injector DI 库,并且一直在关注一些关于围绕命令模式:
Hi I am using the Simple Injector DI library and have been following some really interesting material about an architectural model designed around the command pattern:
- 容器将管理
UnitOfWork
的生命周期,我正在使用命令对数据库执行特定功能.The container will manage the lifetime of the
UnitOfWork
, and I am using commands to perform specific functions to the database.我的问题是,如果我有一个命令,例如
AddNewCustomerCommand
,它又会执行另一个服务的另一个调用(即发送文本消息),从设计的角度来看,这是可以接受的还是应该这可以在更高的层次上完成,如果是这样,如何最好地做到这一点?My question is if I have a command, for example an
AddNewCustomerCommand
, which in turn performs another call to another service (i.e. sends a text message), from a design standpoint is this acceptable or should this be done at a higher level and if so how best to do this?示例代码如下:
public class AddNewBusinessUnitHandler : ICommandHandler<AddBusinessUnitCommand> { private IUnitOfWork uow; private ICommandHandler<OtherServiceCommand> otherHandler; AddNewBusinessUnitHandler(IUnitOfWork uow, ICommandHandler<OtherServiceCommand> otherHandler) { this.uow = uow; this.otherHandler = otherHandler; } public void Handle(AddBusinessUnitCommand command) { var businessUnit = new BusinessUnit() { Name = command.BusinessUnitName, Address = command.BusinessUnitAddress }; var otherCommand = new OtherServiceCommand() { welcomePostTo = command.BusinessUnitName }; uow.BusinessUnitRepository.Add(businessUnit); this.otherHandler.Handle(otherCommand); } }
推荐答案
这取决于您对(业务)命令的架构视图,但是在 用例 和一个命令.在这种情况下,表示层应该(在单个用户操作期间,例如单击按钮)所做的只是创建命令并执行它.此外,它应该只执行单个命令,不能执行更多操作.执行该用例所需的一切都应该由该命令完成.
It depends on your architectural view of (business) commands, but it is quite natural to have a one to one mapping between a Use Case and a command. In that case, the presentation layer should (during a single user action, such as a button click) do nothing more than create the command and execute it. Furthermore, it should do nothing more than execute that single command, never more. Everything needed to perform that use case, should be done by that command.
也就是说,发送文本消息、写入数据库、执行复杂计算、与 Web 服务通信以及运营业务所需的其他一切都应该在该命令的上下文中完成(或者可能排队等待发生)之后).不是之前,也不是之后,因为正是该命令以与演示无关的方式表示需求.
That said, sending text messages, writing to the database, doing complex calculations, communicating with web services, and everything else you need to operate the business' needs should be done during the context of that command (or perhaps queued to happen later). Not before, not after, since it is that command that represents the requirements, in a presentation agnostic way.
这并不意味着命令处理程序本身应该完成所有这些.将许多逻辑移动到处理程序所依赖的其他服务是很自然的.所以我可以想象你的处理程序依赖于
ITextMessageSender
接口,例如.This doesn't mean that the command handler itself should do all this. It will be quite naturally to move much logic to other services where the handler depends on. So I can imagine your handler depending on a
ITextMessageSender
interface, for instance.另一个讨论是命令处理程序是否应该依赖于其他依赖命令处理程序.当您查看用例时,大用例由多个较小的子用例组成的可能性不大,因此从这个意义上说,这并不奇怪.同样,命令和用例之间将存在一对一的映射.
Another discussion is if command handlers should depend on other depend command handlers. When you look at use cases, it is not unlikely that big use cases consist of multiple smaller sub use cases, so in that sense it isn't strange. Again, there will be a one to one mapping between commands and use cases.
但是,请注意,嵌套命令处理程序相互依赖的深度依赖关系图会使代码导航变得复杂,因此请仔细查看此内容.例如,最好注入
ITextSessageSender
而不是使用ICommandHandler
.However, note that having a deep dependency graph of nested command handlers depending on each other, can complicate navigating through the code, so take a good look at this. It might be better to inject an
ITextSessageSender
instead of using anICommandHandler<SendTextMessageCommand>
, for instance.允许处理程序嵌套的另一个缺点是它使基础设施的工作变得更加复杂.例如,当使用添加事务行为的装饰器包装命令处理程序时,您需要确保嵌套处理程序与最外层处理程序在同一事务中运行.我今天碰巧帮助了我的一个客户.这不是很难,但需要一点时间来弄清楚.这同样适用于死锁检测之类的事情,因为它也在事务的边界运行.
Another downside of allowing handlers to nest, is that it makes doing infrastructural stuff a bit more complex. For instance, when wrapping command handlers with a decorator that add transactional behavior, you need to make sure that the nested handlers run in the same transaction as the outer most handler. I happened to help a client of me with this today. It's not incredibly hard, but takes a little time to figure out. The same holds for things like deadlock detection, since this also runs at the boundary of the transaction.
此外,死锁检测是展示这种命令/处理程序模式强大功能的一个很好的例子,因为几乎所有其他架构风格都无法插入这种行为.查看 这篇文章) 查看示例.
Besides, deadlock detection is an great example to show case the power of this command/handler pattern, since almost every other architectural style will make it impossible to plug-in this behavior. Take a look at the
DeadlockRetryCommandHandlerDecorator
class in this article) to see an example.这篇关于从另一个命令 Handle() 方法中调用命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!