【问题标题】:Calling commands from within another command Handle() method从另一个命令 Handle() 方法中调用命令
【发布时间】:2012-06-08 14:19:48
【问题描述】:

您好,我正在使用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);
     }
}

【问题讨论】:

    标签: c# .net architecture dependency-injection unit-of-work


    【解决方案1】:

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

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

    这并不意味着命令处理程序本身应该完成所有这些。将很多逻辑转移到处理程序所依赖的其他服务是很自然的。所以我可以想象你的处理程序依赖于ITextMessageSender 接口,例如。

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

    但是,请注意,嵌套命令处理程序相互依赖的深度依赖图可能会使代码导航变得复杂,因此请仔细研究一下。例如,注入ITextSessageSender 而不是使用ICommandHandler&lt;SendTextMessageCommand&gt; 可能会更好。

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

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

    【讨论】:

    • 那么如何防止从命令处理程序分派的命令执行那些死锁或事务装饰器?
    • 你要么必须阻止装饰器被应用到嵌套处理程序(这通常很难用任何 DI 容器实现),要么让装饰器本身检测它已经在事务的上下文。另一种选择是给嵌套处理程序自己的抽象。这使得仅将装饰器应用于外部处理程序变得微不足道。
    猜你喜欢
    • 1970-01-01
    • 2017-02-26
    • 1970-01-01
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多