GRASP之控制器模式 - Kamil Grzybek

19-09-05 banq
              

问题:UI层之外的第一个对象是否接收并协调“控制”系统操作?

解决方案:将责任分配给表示以下选项之一的对象:

  • - 表示整个“系统”,“根对象”,运行软件的设备或主要子系统(这些都是外观控制器的变体)
  • -表示发生系统操作的用例场景(用例或会话控制器)

这个原则实现取决于我们系统的高级设计,但一般我们需要定义协调我们的业务事务处理的对象。乍一看,似乎Web应用程序/ API中的MVC控制器在这里是一个很好的例子(即使名称是相同的)但对我来说并非如此。当然它接收输入但它不应该协调系统操作 - 它应该将它委托给单独的服务或命令处理程序:

public class CustomerOrdersController : Controller
{
    private readonly IMediator _mediator;

    public CustomerOrdersController(IMediator mediator)
    {
        this._mediator = mediator;
    }

    /// <summary>
    /// Add customer order.
    /// </summary>
    /// <param name="customerId">Customer ID.</param>
    /// <param name="request">Products list.</param>
    [Route("{customerId}/orders")]
    [HttpPost]
    [ProducesResponseType((int)HttpStatusCode.Created)]
    public async Task<IActionResult> AddCustomerOrder(
        [FromRoute]Guid customerId, 
        [FromBody]CustomerOrderRequest request)
    {
       await _mediator.Send(new AddCustomerOrderCommand(customerId, request.Products));

       return Created(string.Empty, null);
    }
}

public class AddCustomerOrderCommandHandler : IRequestHandler<AddCustomerOrderCommand>
{
    private readonly ICustomerRepository _customerRepository;
    private readonly IProductRepository _productRepository;
    private readonly IForeignExchange _foreignExchange;

    public AddCustomerOrderCommandHandler(
        ICustomerRepository customerRepository, 
        IProductRepository productRepository, 
        IForeignExchange foreignExchange)
    {
        this._customerRepository = customerRepository;
        this._productRepository = productRepository;
        this._foreignExchange = foreignExchange;
    }

    public async Task<Unit> Handle(AddCustomerOrderCommand request, CancellationToken cancellationToken)
    {
        // handling...
    }
}