事件总线就是订阅/发布模式的一种实现 事件总线就是为了降低耦合
1.比如在winform中 到处都是事件
触发事件的对象 sender
事件的数据 e
事件的处理逻辑 方法体
通过EventBus实现事件对象和处理逻辑的解耦
1.抽离事件对象 发生时间的事件 触发事件的对象源(可选)
//
// 摘要:
// Defines interface for all Event data classes.
public interface IEventData
{
//
// 摘要:
// The time when the event occured.
DateTime EventTime { get; set; }
//
// 摘要:
// The object which triggers the event (optional).
object EventSource { get; set; }
2.抽离事件的处理对象
public interface IEventHandler
{
}
public interface IEventHandler<in TEventData> : IEventHandler
{
/// <summary>
/// Handler handles the event by implementing this method.
/// </summary>
/// <param name="eventData">Event data</param>
void HandleEvent(TEventData eventData);
}
3.所有EventData跟EventHandler不再耦合 全都跟EventBus进行通信
在EventBus中有一个字典进行存放 EventData类型跟需要触发的Handler对象
这里的Type就是EventData List
private readonly ConcurrentDictionary<Type, List<IEventHandlerFactory>> _handlerFactories;
4.ABP的EventBus封装的比较高深 自己来个简洁版 思想是一样的(这里还存在很多问题 比如并发 往字典存放数据没有加锁等问题 具体的看ABP)
ABP初始化的时候会把所有的EventData和EventHandler对应存放到字典中 也可以通过Unregister移除某一个Handler
public class EventBus : IEventBus
{
public EventBus()
{
mapDic = new ConcurrentDictionary<Type, List<Type>>();
}
//EventBus单例模式
public static EventBus Default = new EventBus();
//存储EventData和EventHandle的映射关系(没有存放handler的实例而是存放metaData,然后通过反射调用)
private ConcurrentDictionary<Type, List<Type>> mapDic;
public void Register<TEventData>(Type handlerType) where TEventData : IEventData
{
//将数据存储到mapDic
var dataType = typeof(TEventData);
Register(dataType, handlerType);
}
public void Register(Type eventType, Type handlerType)
{
if (mapDic.Keys.Contains(eventType))
{
if (!mapDic[eventType].Contains(handlerType))
{
mapDic[eventType].Add(handlerType);
}
}
else
{
mapDic[eventType] = new List<Type>() { handlerType };
}
}
public void Unregister<TEventData>(Type handler) where TEventData : IEventData
{
var dataType = typeof(TEventData);
Unregister(dataType, handler);
}
public void Unregister(Type eventType, Type handlerType)
{
if (mapDic.Keys.Contains(eventType))
{
if (mapDic[eventType].Contains(handlerType))
{
mapDic[eventType].Remove(handlerType);
}
}
}
public void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData
{
var dataType = eventData.GetType();
//获取当前的EventData绑定的所有Handler
var handlerTypes = mapDic[dataType];
foreach (var handlerType in handlerTypes)
{
var methodInfo = handlerType.GetMethod("EventHandle");
if (methodInfo != null)
{
// var handler = Assembly.GetExecutingAssembly().CreateInstance(handlerType.FullName);
var handler = Activator.CreateInstance(handlerType);
//执行所有的Handler方法
methodInfo.Invoke(handler, new object[] { eventData });
}
}
}
}
提供了EventData和Handler的绑定 也可以移除指定的Handler
通过调用.Trigger() 然后当前的EventData类型在字典中找到当前类型的所有Handler 执行所有Handler的处理方法
事件总线通过 EventBusInstaller 来注册 EventBus 和监听事件。 每当IocContainer注册一个类型后 会判断当前类型是否实现IEventHandler 获取具体的EventData类型在EventBus上进行注册
private void Kernel_ComponentRegistered(string key, IHandler handler)
{
/* This code checks if registering component implements any IEventHandler<TEventData> interface, if yes,
* gets all event handler interfaces and registers type to Event Bus for each handling event.
*/
if (!typeof(IEventHandler).GetTypeInfo().IsAssignableFrom(handler.ComponentModel.Implementation))
{
return;
}
var interfaces = handler.ComponentModel.Implementation.GetTypeInfo().GetInterfaces();
foreach (var @interface in interfaces)
{
if (!typeof(IEventHandler).GetTypeInfo().IsAssignableFrom(@interface))
{
continue;
}
var genericArgs = @interface.GetGenericArguments();
if (genericArgs.Length == 1)
{
_eventBus.Register(genericArgs[0], new IocHandlerFactory(_iocResolver, handler.ComponentModel.Implementation));
}
}
}
在ABP中使用EventBus
1.定义自己的数据对象
public class MyEventData : EventData
{
public string Name { get; set; }
}
2.定义自己的处理事件Handler
public class MyEventHandler : IEventHandler<MyEventData>, ITransientDependency
{
public ILogger Logger { set; get; }
public MyEventHandler()
{
Logger = NullLogger.Instance;
}
public void HandleEvent(MyEventData eventData)
{
Logger.Info($"这是{eventData.Name}自定义的HandEvent处理事件");
}
}
3.通过属性注入 或者构造函数注入 或者直接用静态实例
public class TaskAppService : ApplicationService
{
public IEventBus EventBus { get; set; }
public TaskAppService()
{
EventBus = NullEventBus.Instance;
}
public void CompleteTask(CompleteTaskInput input)
{
EventBus.Trigger(new MyEventData {Name= "abc123"});
}
}
EventBus.Default.Trigger(new MyEventData {Name= "abc123"});