深入浅出制作全自动Mud机器人-事件总线
-
事件系统是一种很常见的代码结构。从web开发,GUI软件制作到各种系统,事件系统都是重要的组成部分。
事件总线是指将所有的事件的抛出与监听都挂在一个独立的类(EventBus或者EventBridge)上。
事件系统是天然的解耦合工具,底层代码抛出事件,处理代码接受事件,让人极容易的写出互相之间不依赖的代码。
写机器,自己嵌入一套事件系统是很顺理成章的事情,甚至某些客户端会在客户端内部实现一个全局的事件系统。
但是,就如同《人月神话》中提到过“没有银弹”。极度的自由,很容易带来极度的混乱。滥用事件很容易带来代码组织架构上的混乱,虽然解耦合了,但依然维护苦难。
毕竟我们强调解耦合是为了优化结构,降低维护难度。低耦合还有下半句高内聚。事件系统虽然实现了低耦合,但在内聚上做的一塌糊涂,必须极为注意使用。
事件的处理要有流向性
处理事件最怕的是循环调用,处理程序互相之间调用,织成一张网,如同乱成一团的线头一样,让人无法入手。
从我的角度,我一直推崇代码的架构要分层,比如我使用的一种架构
代码之间,要有严格的上下级关系,调用原则,避免相互依赖,依靠各种依赖注入/装饰类/代理类来实现反向的交互。
这种情况下,我们要有自我约束,事件的监听函数的调用过程,本质应该是一个水向下流,或者水蒸汽向上飘的单向过程。
事件的生产方和事件的消费方要有严格的上下关系。
这样事件的使用就会有头,有尾,能够梳理。
事件应该是业务的封装而非调用的信号
不同系统使用事件要解决的问题是不一样的。
对于Mud来说,事件应该是对实际发生的业务的抽象与封装
比如新的文字行,比如断开连接和建立连接,比如用户的点击操作等。
事件的生产方本质是把各种现实意义发生的元素,抽象成代码,封装成同一的格式,交给流水线。
不应该觉得为了调用一个处理函数,而抛一个事件。抛事件时一定要明确,很可能没有代码接受事件,或者有乱序的多个代码会接受事件。
如果需要明确的调用代码,不应该使用消息,应该使用显性的注册(依赖注入)机制,调用注册点中注册的代码,做明确的显性的调用。
事件处理函数不要抛出事件。
完整的说,事件处理函数,不要在同一个总线(bus,事件的监听系统)上抛出一个不同组的事件。
因为,每个事件,都会有0个或者多个处理函数,在这些处理函数上再抛出事件,会无法确定是否有循环调用,顺序问题以及依赖问题。
我认为唯一适合事件再抛出事件的,是对事件细化扩展为同组的子事件。
比如登陆成功事件,可以细化为 首次登陆 和 重新登陆事件
这就是同组的事件,(任意登陆/首次登陆/重新登陆)
监听程序会明确的监听其中一个,而不会每个都监听。
其他情况我不建议事件再触发时间,混乱度会字数成长。
总结
事件总线系统,是Mud机器人中必不可少的。
事件总线系统,极为强大。
事件总线系统,过于强大,容易混乱,必须有原则有策略的去规范使用。
-
J jarlyyn 在 引用了 此主题