CQRS - 避免切换大小写调用命令处理程序

CQRS - Avoid switch case to call command handler

我正在使用 CQRS 设计模式。我有超过 15 个命令处理程序对应于每个事件类型。我想避免下面的 switch case 来根据事件类型调用相应的命令处理程序。

这是我的 Azure 函数:

[FunctionName("ReceiveEvent")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            //log.LogInformation("ReceiveEvent HTTP trigger function started processing request.");

            //log.LogInformation($"Pushing Events to Azure Blob on storage account :-{CloudConfigurationManager.GetSetting("AzureWebJobsStorage")}");

            IActionResult actionResult = null;

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

            var command = await _commandMapper.Map(requestBody);

            if (_commandValidator.Validate(req, command, ref actionResult))
            {
                switch (command.EventType)
                {
                    case EventType.CARD_BLOCK:
                        _cardBlockCommandHandler.Handle(command as CardBlockCommand);
                        break;
                    case EventType.CARD_CANCEL:
                        _cardCancelledCommandHandler.Handle(command as CardCancelledCommand);
                        break;
                    case EventType.CARD_UNBLOCK:
                        _cardUnBlockHandler.Handle(command as CardUnBlockCommand);
                        break;

                }
                //TODO
                return actionResult;
            }

有没有更好的方法来避免这种情况?

命令处理程序:

public class CardBlockCommandHandler : ICommandHandler<CardBlockCommand>
    {
        private readonly IAzureBlobStorage _azureBlobStorage;

        public CardBlockCommandHandler(IAzureBlobStorage azureBlobStorage)
        {
            _azureBlobStorage = azureBlobStorage;
        }

        public void Handle(CardBlockCommand command)
        {
            try
            {
                //TODO: Store into blob
                //_azureBlobStorage.UploadMessageContentAsync(storageConnectionString: string.Empty,
                //    storageContainerName: string.Empty, blobName: string.Empty, content: string.Empty);

                throw new NotImplementedException();
            }
            catch
            {

            }
        }
    }

ICommandHandler:

public interface ICommandHandler<TCommand> where TCommand : ICommand
    {
        /// <summary>
        /// Execute command
        /// </summary>
        /// <param name="command"></param>
        void Handle(TCommand command);
    }

命令:

public abstract class Command : ICommand
    {
        public EventType EventType { get; }
    }

public interface ICommand
    {
        EventType EventType { get;  }
    }

这是在详细说明评论中提到的关于使用服务的内容。有一个 ICommandHandlerService 作为依赖注入到你的函数构造函数中(你正在使用 DI 容器,不是吗?)。此接口将具有以下方法:

void HandleCommand(ICommand command);

ICommandHandlerService 的实现将在事件类型和 CommandHandlers 之间有一个字典映射,例如

public class CommandHandlerService : ICommandHandlerService 
{
     Dictionary<EventType, ICommandHandler> handlerDictionary = new Dictionary<EventType, ICommandHandler>(); 
//assuming that all your different handlers implement ICommandHandler ?

     public void CommandHandlerService()
     {
        handlerDictionary.Add(EventType.CARD_UNBLOCK, new CardUnBlockCommandHandler());
        handlerDictionary.Add(EventType.CARD_BLOCK, new CardBlockCommandHandler());
        //setup rest of your associations
     }

}

void HandleCommand(ICommand command)
{
    if(!handlerDictionary.ContainsKey(command.EventType))
    {
       //throw suitable exception ?
    } 

    var commandHandler = handlerDictionary[command.EventType];
    commandHandler.Handle(command);
}

您的 Azure 函数构造函数将由您的 DI 框架传入 ICommandHandlerService 实例,您可以这样称呼它:

if (_commandValidator.Validate(req, command, ref actionResult))
{
    commandHandlerService.Handle(command);
}