从另一个命令 Handle() 方法中调用命令

本文关键字:命令 方法 调用 另一个 Handle | 更新日期: 2023-09-27 18:36:31

嗨,我正在使用简单注入器 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);
     }
}

从另一个命令 Handle() 方法中调用命令

这取决于您对(业务)命令的架构视图,但在用例和命令之间进行一对一映射是很自然的。在这种情况下,表示层应该(在单个用户操作期间,例如按钮单击)只执行创建命令并执行它。此外,它应该只执行该单个命令,而不是更多。执行该用例所需的一切都应由该命令完成。

也就是说,发送文本消息、写入数据库、执行复杂的计算、与 Web 服务通信以及操作业务需求所需的所有其他操作都应在该命令的上下文中完成(或者可能排队等待稍后发生)。不是之前,也不是之后,因为正是该命令以与表示无关的方式表示需求。

这并不意味着命令处理程序本身应该执行所有这些操作。将许多逻辑移动到处理程序所依赖的其他服务是很自然的。因此,我可以想象您的处理程序依赖于ITextMessageSender接口。

另一个讨论是命令处理程序是否应依赖于其他依赖命令处理程序。当您查看用例时,大型用例由多个较小的子用例组成的可能性不大,因此从这个意义上说,这并不奇怪。同样,命令和用例之间将有一个一对一的映射。

但是,请注意,嵌套命令处理程序相互依赖的深度依赖关系图可能会使代码导航复杂化,因此请仔细查看此内容。例如,注入ITextSessageSender而不是使用ICommandHandler<SendTextMessageCommand>可能更好。

允许处理程序嵌套的另一个缺点是,它使基础设施工作变得更加复杂。例如,当使用添加事务行为的装饰器包装命令处理程序时,需要确保嵌套处理程序与最外层处理程序在同一事务中运行。我今天碰巧帮了我的一个客户。这不是非常困难,但需要一点时间来弄清楚。死锁检测等内容也是如此,因为它也在事务的边界上运行。

此外,死锁检测是一个很好的例子,可以展示这种命令/处理程序模式的强大功能,因为几乎所有其他架构风格都无法插入这种行为。查看本文中的DeadlockRetryCommandHandlerDecorator类)以查看示例。