事件总线EventBus设计思路学习笔记

事件总线EventBus设计思路学习笔记


文章目录


前言

1.简单介绍事件总线这个概念对您来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉。事件总线是对发布-订阅模式的一种实现。它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需要相互依赖,达到一种解分解的目的。我们来看看事件总线的处理流程:事件总线就相当于一个介于发布者和订阅者中间的主轴。它隔离了出版物和订阅者之间的直接依赖,接管了所有事件的发布和订阅逻辑,并负责事件的中转。
2.实现原理
3.事件总线的实现要点事件总线维护一个事件源与事件处理的映射字典;通过单例模式,确保事件总线的唯一入口;利用反射或依赖注入完成事件源与事件处理的初始化绑定。


一、发布订阅模式

发布方:被观察者:当状态改变时负责通知所有订阅者。
订阅方:观察者,订阅事件并对接收到的事件进行处理。
实现方式:
简单的实现方式:由Publisher维护一个订阅者列表,当状态改变时循环遍历列表通知订阅者。
委托的实现方式:由Publisher定义事件委托,Subscriber实现委托。

二、实现事件总线这个模式的简易步骤

1.事件发布方定义事件委托

2.事件订阅方定义事件处理逻辑

3.显示订阅事件


三、思考问题

1.想要精简步骤,那我们需要寻找共性。共性就是事件的本质,也就是我们针对事件源和事件处理提取出来的两个接口。

2.想要解除依赖,那就要在发布方和订阅方之间添加一个中介。

3.想要避免订阅者同时处理过多事件逻辑,那我们就把事件逻辑的处理提取到订阅者外部。

四、事件总线初版–发布订阅模式

阶段一

1.观察者,持有被观察者成员,被观察者成员的委托是观察者的某个方法,在运行时将该方法与被观察者成员的委托定义绑定,每个委托方法由每个观察者所定义,委托方法放在观察者上,委托的具体事件处理放在被观察者上。

2.观察者初始化一个被观察者成员,将被观察者的委托方法赋值为观察者定义的具体委托事件,被观察者定义的委托方法包括:①事件源:委托传的参数(与两者都有关),②事件处理:委托实例(观察者的具体委托事件)

阶段一问题点:被观察者作为观察者的成员,耦合性高,如果换个场景,要重新定义委托,重新定义事件处理,重新定义事件源

1.提取事件源,包含事件发生的时间和触发事件的对象,用于参数传递
2.接口(抽象) + 继承(扩展)
3.用接口去抽象出来事件源
4.用继承去扩展事件的独特属性(不能抽象的属性)

阶段二

处理办法

1.提取事件处理器
2.定义事件处理器公共接口,所有的事件处理都实现该接口
3.定义泛型事件处理器接口,将事件源与事件处理绑定,并实现公共接口,绑定形式:原:定义方法 + 参数,现:定义接口(抽象方法) + 泛型(抽象参数)
4.观察者方实现泛型事件处理器接口,实现处理器方法

问题点

1.发布方和订阅方之间直接依赖
2.直接在订阅者中实现IEventHandler接口处理多个事件逻辑不太合适,违法单一职责原则

暴露的三个问题

1.如何精简步骤?
2.如何解除发布方与订阅方的依赖?
3.如何避免在订阅者中同时处理多个事件逻辑?

带问题思考

1.共性:想要精简步骤,那我们需要寻找共性。共性就是事件的本质,也就是我们针对事件源和事件处理提取出来的两个接口。
2.中介:想要解除依赖,那就要在发布方和订阅方之间添加一个中介。
3.外部:想要避免订阅者同时处理过多事件逻辑,那我们就把事件逻辑的处理提取到订阅者外部。

如何避免在订阅者中同时处理多个事件逻辑?

观察者不能直接实现泛型事件处理接口,应该将观察者内的具体事件处理方法提取出来,并实现该泛型接口,绑定关系在订阅者(观察者)绑定时体现,不在订阅者(观察者)类里写绑定关系

如何精简步骤?

1.在被观察者构造函数中通过反射去进行事件源和事件处理的绑定
2.不需要通过事件委托触发,直接通过事件总线触发即可

阶段二处理办法

定义事件总线接口
事件总线构造函数

事件总线初始化实例,在构造函数内绑定,获取实现IEventHandler该接口的所有泛型接口"IEventHandler’1",将实现该泛型接口的实现类(事件处理、key)和泛型类(事件源、value)用ConcurrentDictionary<Type, List> _eventAndHandlerMapping以键值对的方式存储,key:事件源,value:事件处理。

注册所有实现IEventHandler的泛型接口和它们的泛型类型(通过数组获取泛型接口指定的参数类型)
通过初始化绑定事件处理器和事件源的方法可以从事件处理的构造函数中抽出来
抽出来的目的有:
事件处理与事件总线绑定实现动作解耦
将事件总线注册进Container中

做法:
定义一个事件总线安装器EventBusInstaller类,自动注册所有的事件处理程序到依赖注入容器中
实现IWindsorInstaller接口,只有一个实现方法:安装方法Install
成员:
依赖注入容器解析器_iocResolver
事件总线配置器_eventBusConfiguration
事件总线_eventBus

构造函数

参数:依赖注入容器解析器_iocResolver
使用依赖注入容器解析器_iocResolver解析事件总线配置器_eventBusConfiguration

事件总线安装方法Install

使用Castle.Windsor的接口IWindsorContainer的注册方法注册IEventBus以及它的实现类EventBus(单例)
使用依赖注入容器解析器_iocResolver解析事件总线_eventBus
定义Castle.MicroKernel接口IKernelEvents的组件注册事件
自动注册所有实现了接口IEventHandler的类型到事件总线中
遍历注册(绑定事件源和事件处理器)
调用事件总线的Register注册(绑定事件源和事件处理器)的方法

IocManager的IocContainer调用Install方法,传入新创建的实例EventBusInstaller对象(传入IocManager(事件总线安装器的解析器)),IocContainer的Install方法也就是事件总线的安装方法Install

线程安全集合
ConcurrentDictionary<Type, List> _eventAndHandlerMapping可由多个线程同时访问的键/值对的线程安全集合

手动绑定事件源与事件处理
Register<事件源>(事件处理)

手动解除事件源与事件处理的绑定
UnRegister<事件源>(事件处理)

根据事件源触发绑定的事件处理
获取key为该事件源的所有事件处理类
遍历事件处理类集合(允许一个事件对应多个事件处理程序)
获取该类中的HandleEvent方法
若方法(替身)存在,创建该方法的参数实例,调用Invoke使替身自己调用该方法

总结

没贴代码,感兴趣的可以私聊,小弟我班门弄斧,其实还是半桶水,还在学习,请各位大佬多多指正!

本篇文章会随代码迭代持续更新!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值