避免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);
}
}
这在 IEvent
和 IEventHandler
之间引入了一些耦合,实际上它们是单个协议中的两个参与者(角色)。
我们有超过 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);
}
}
这在 IEvent
和 IEventHandler
之间引入了一些耦合,实际上它们是单个协议中的两个参与者(角色)。