避免Event Dispatcher中的switch case调用对应的Event Handler

Avoid switch case in Event Dispatcher to call corresponding Event Handler

我们有超过 15 个事件处理程序对应于每个事件类型。我想避免在 Event Dispatcher 中使用以下 switch case 来根据事件类型调用相应的事件处理程序。

这是我的事件调度程序 class:

public class EventDispatcher : IEventDispatcher
    {
        private readonly IServiceProvider _serviceProvider;
        public EventDispatcher(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public async Task<ResultDto> HandleEvent(IEvent @event, ILogger logger)
        {
            ResultDto resultDto = null;
            switch (@event.EventType)
            {
                case EventType.CARD_BLOCK:
                    resultDto = await HandleAsync<CardBlockedEvent>(@event as CardBlockedEvent, logger);
                    break;
                case EventType.CARD_UNBLOCK:
                    resultDto = await HandleAsync<CardUnBlockedEvent>(@event as CardUnBlockedEvent, logger);
                    break;
                case EventType.CARD_CANCEL:
                    resultDto = await HandleAsync<CardCancelledEvent>(@event as CardCancelledEvent, logger);
                    break;
                case EventType.CARD_GROUP_CHANGED:
                    resultDto = await HandleAsync<CardGroupChangedEvent>(@event as CardGroupChangedEvent, logger);
                    break;
                case EventType.CARD_EXPIRY:
                    resultDto = await HandleAsync<CardExpiredEvent>(@event as CardExpiredEvent, logger);
                    break;
                default:
                    logger.Warning($"Unknown event type");
                    resultDto = new ResultDto { ResultType = ResultType.Failure, Message = "Unknown event type" };
                    break;
            }
            return resultDto;
        }
        private async Task<ResultDto> HandleAsync<TEvent>(TEvent @event, ILogger logger) where TEvent : IEvent
        {
            var handler = _serviceProvider.GetService(typeof(IEventHandler<ResultDto, TEvent>)) as IEventHandler<ResultDto, TEvent>;
            return await handler.HandleAsync(@event, logger);
        }

    } 

下面是依赖注册:

 public class EventHandlerIoCRegistrations : IRegisterSevices
    {
        public void RegisterServicesWith(IServiceCollection serviceCollection)
        {
            RegisterDispatcher(serviceCollection);
            RegisterHandlers(serviceCollection);
        }
        private void RegisterDispatcher(IServiceCollection serviceCollection)
        {
            serviceCollection.AddTransient<IEventDispatcher, EventDispatcher>();
        }

        private void RegisterHandlers(IServiceCollection serviceCollection)
        {
            Assembly.GetExecutingAssembly()
            .GetTypes()
            .Where(item => item.GetInterfaces()
            .Where(i => i.IsGenericType).Any(i => i.GetGenericTypeDefinition() == typeof(IEventHandler<,>)) && !item.IsAbstract && !item.IsInterface)
            .ToList()
            .ForEach(assignedTypes =>
            {
                var serviceType = assignedTypes.GetInterfaces().First(i => i.GetGenericTypeDefinition() == typeof(IEventHandler<,>));
                serviceCollection.AddScoped(serviceType, assignedTypes);

            });
        }
    }

下面是事件处理接口:

public interface IEventHandler<TResult, TEvent>
        where TEvent : IEvent
        where TResult : class
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="event"></param>
        /// <param name="logger"></param>
        /// <returns></returns>
        Task<TResult> HandleAsync(TEvent @event, ILogger logger);
    }

有没有更好的方法来避免这种情况? 有什么想法吗?

您可能想介绍一些 polymophic statc binding 的风味。

考虑

public interface IEvent {
  // ...
  
  // Here's the magic
  void HandleMe(IEventHandler target);
}

// Arbitrary examples
public class CardBlockedEvent : IEvent {
  // ...
  void HandleMe(IEventHandler target);
    target.HandleAsync<CardBlockedEvent>(this);
  }
}

public class CardUnBlockedEvent : IEvent {
  // ...
  void HandleMe(IEventHandler target);
    target.HandleAsync<CardUnBlockedEvent>(this);
  }
}

这在 IEventIEventHandler 之间引入了一些耦合,实际上它们是单个协议中的两个参与者(角色)。