.NET 事件总线
读完圣杰大佬的事件总线归纳总结的,只读了第一节,有空看一下第二节,有空梳理一下记录的笔记,下面是自己总结的步骤,后期会整理
说是自己没有时间,其实是自己把时间都浪费掉了,这个是个坏毛病,要改,慢慢改变一下吧,
demo如下:gitee地址
渔夫钓鱼,需要抽离事件源,和事件处理
一.这就是简单的发布订阅模式,第一版
1.先定义鱼的种类
2.定义鱼竿类
3.在鱼竿类写委托(需要参数,鱼的种类)与事件,定义一个方法用于触发事件
ThrowHook 下钩
3.定义一个垂钓者类,定义一个垂钓者名称,定义一个钓鱼的数量,定义一个被观察者对象(鱼竿),定义一个方法调用鱼竿的下杆的方法,定义一个方法和鱼竿的事件绑定的方法
4.改造鱼竿类的下杆的方法,先写上注释,开始下杆,判断当前随机数是否能除尽2如果除尽,则定义一个随机数,将鱼的类型随机一下,然后传给事件中去
二.抽象事件源,和事件处理
第一步,先改造事件源
1.先处理事件源,事件源就是鱼的类型,鱼的类型太过具体了,我们需要定义一个接口将它解耦,
事件源包含触发事件的对象和触发事件的时间,我们先定义一个接口,放这两个字段
2.定义一个EventData,继承于IEventData,创建一个构造函数,将触发事件的事件赋值当前时间
3.扩展一个当前钓鱼的对象,继承于EventData,为FishingData,包含两个属性,一个是鱼的种类,一个是垂钓者对象
4.将当前的事件源全部替换为当前FishingData事件源
把在FishingRod声明的委托参数类型改为FishingEventData类型了,即public delegate void FishingHandler(FishingEventData eventData); //声明委托;
然后修改FishingMan的Update方法按委托定义的参数类型修改即可
第二步,改造事件处理
1.定义一个事件处理器的公共接口:IEventHandler
2.定义一个泛型事件处理器接口IEventHandler,用于统一命名事件处理方法名,泛型接口的泛型类必须继承于IEventData,定义的事件处理方法名称为HandleEvent
3.将fishingman继承于IEventHandler
这个发布订阅模式已经可以正常使用了
但是为了更大限度的解耦,我们需要在订阅者和发布者中间添加一个中介,想要避免订阅者同时处理多事件逻辑,我们就把事件逻辑的处理提取到订阅者外部
第三步,如何避免在订阅者中同时处理多个事件逻辑
自然是针对不同的事件源IEventData实现不同的IEventHandler
这时我们就可以移除在FishingMan中实现的IEventHandler接口了。
然后将事件注册改为fishingRod.FishingEvent += new FishiningEventHandler().HandleEvent;即可。
第四步,统一注册事件,精简流程
在FishingRod中写构造函数
(1)获取当前程序集所有信息
(2)获取当前程序集所有类型,通过遍历
(3)判断当前类型是否实现了IEventHandler接口
(4)如果实现了,就获取当前类型的IEventHandler泛型接口
(5)若是不为空,则获取当前接口的参数
(6)获取之后,用当前类型匹配是否等于FishingData
(7)创建当前类型的实例,并且将它转换为IEventHandler
(8)将当前类型的处理事件绑定在当前事件中
第五步,解除依赖,事件总线登场
1.定义一个EventBus,事件总线类
2.准备一个字段,Default,就是当前EventBus的实例
3.定义一个线程安全字典集合,键是Type,值是List
4.定义一个无参构造函数,初始化字典集合,初始化MapEventToHandler方法
5.定义一个MapEventToHandler方法,
6.MapEventToHandler逻辑
(1).首先获取当前程序集
(2).获取所有类型,遍历
(3).判断当前类型是否实现了IEventHandler
(4).获取当前类型的泛型接口handlerInterface
(5).判断当前泛型接口handlerInterface不为空,则获取当前接口的泛型参数eventDataType
(6).判断当前类里的字典集合里是否包含当前eventDataType,
(7).如果包含则将当前eventDataType里的值取出来,组成新的List
(8).并且将当前的类型也存入这个list中,
(9).将当前组成的这个list存入字典集合中
(10).如果不包含eventDataType,则将当前的类型组成一个list
(11).最后将当前的eventDataType为键,list为值存入字典集合中
7.再写一个触发方法Trigger
(1).并且用泛型约束,当前泛型参数必须继承于IEventData
(2).根据当前的泛型参数,从字典中取出它对应的值,也就是实现于泛型接口的类,组成一个list
(3).判断当前list不为空,并且个数大于0
(4).则遍历当前集合
(5).用MethodInfo去接收当前方法名称是HandleEvent的方法
(6).如果当前方法不为空,则依据当前的类型,创建一个实例,
(7).通过当前方法.Invoke直接调用方法,并且传入参数,就是我们的入参