您好我正在使用Simple Injector DI库并且一直在关注围绕命令模式设计的架构模型的一些非常有趣的材料:
容器将管理UnitOfWork
的生命周期,我正在使用命令来执行数据库的特定功能。
我的问题是,如果我有一个命令,例如一个AddNewCustomerCommand
,它又会对另一个服务执行另一个调用(即发送文本消息),从设计的角度来看这是可以接受的,还是应该这样做?在更高的水平,如果是这样,如何最好地做到这一点?
示例代码如下:
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);
}
}
答案 0 :(得分:16)
这取决于(业务)命令的架构视图,但在Use Case和命令之间进行一对一映射是很自然的。在这种情况下,表示层应该(在单个用户操作期间,例如按钮单击)只执行创建命令并执行它。此外,它应该只执行单个命令,而不是更多。执行该用例所需的一切都应该通过该命令完成。
也就是说,发送文本消息,写入数据库,进行复杂的计算,与Web服务进行通信以及操作业务所需的其他所有内容都应该在该命令的上下文中完成(或者可能排队等待后来)。不是之前,而是之后,因为它是以表示不可知的方式表示要求的命令。
这并不意味着命令处理程序本身应该完成所有这些。将很多逻辑移动到处理程序所依赖的其他服务是很自然的。所以我可以想象你的处理程序取决于ITextMessageSender
接口,例如。
另一个讨论是命令处理程序是否应该依赖于其他依赖命令处理程序。当您查看用例时,大用例不一定包含多个较小的子用例,因此从这个意义上来说并不奇怪。同样,命令和用例之间将存在一对一的映射。
但是,请注意,依赖于彼此的嵌套命令处理程序的深度依赖关系图可能会使代码导航变得复杂,因此请仔细查看。例如,注入ITextSessageSender
而不是使用ICommandHandler<SendTextMessageCommand>
可能更好。
允许处理程序嵌套的另一个缺点是,它使基础结构的东西变得更复杂一些。例如,在使用添加事务行为的装饰器包装命令处理程序时,需要确保嵌套处理程序在与最外层处理程序相同的事务中运行。今天我碰巧帮助了我的客户。这并不难,但需要一点时间才能搞清楚。死锁检测也是如此,因为它也在事务的边界运行。
此外,死锁检测是一个很好的例子来展示这个命令/处理程序模式的强大功能,因为几乎所有其他架构风格都会使插入这种行为变得不可能。看一下this article中的DeadlockRetryCommandHandlerDecorator
课程,看一个例子。