作者:聂勇 欢迎转载,请保留作者信息并说明文章来源!
提到事件驱动,熟悉Java的童鞋会想到Java Swing中的事件模型:按钮的按下、释放;鼠标在窗口的移入、移出;输入框被做焦点、失去焦点、输入,都会要求编写一个事件监听器。
事件驱动有几个用途:
- 实现模块间的松耦合。
- 将一个大的业务场景拆分成几个独立的小部分。
- 提供扩展点,实现插件机制的功能。
- 用于异步操作场景。
例如,一个用户登陆的业务场景:用户执行登陆操作后,会进行用于登陆成功率的统计日志输出,如果登陆成功需要通知用户在线模块某一个用户成功登陆了。
用事件驱动非常方便解决上述问题:执行登陆操作后,产生一个登陆事件,编写两件事件监听器(一个处理登陆成功率的统计日志输出,一个通知用户在线模块)注册到登陆事件。如果后续在用户执行登陆后还有新的业务需求,只需编写新的事件监听器注册到登陆事件。这样的做法符合开闭原则,实现新的功能不影响已有功能。如果要移除某个功能点,直接移除对应的事件监听器。
如果查找事件驱动的实现机制,网上查到的大部分都是类似于下面的“经典事件驱动模式”的说明。但在实际的业务场景中,这样的实现不能满足需求,后面有一个”改进版事件驱动模式”。当然,需要再进一步改进才能满足实际中的需求,例如:异步执行,线程池,事件与事件监听器的注册配置,运行状态监控等等。
经典事件驱动模式
经典的事件驱动有三个基本元素:
- 事件源:负责事件监听器的管理,创建并派发事件。
- 事件监听器:接收并处理事件。
- 事件。
Event源代码
|
|
EventListener源代码
|
|
EventSource源代码
|
|
ClientMain源代码
|
|
执行ClientMain类后的结果类似如下:
监听器:ClientMain$HelloWorldListener@45bab50a接收到事件,事件附带的数据:hello, world!
监听器:ClientMain$SimpleListener@7150bd4d接收到事件,事件附带的数据:hello, world!
改进版事件驱动模式
在经典版的基础上,将EventSource按职责进行拆分,一部分(EventSource)负责事件派分,另一部分(EventManagement)负责事件的管理(添加事件、移除事件、获取指定事件的监听器列表)。并且实现了向不同的事件注册各自的监听器。
Event源代码
|
|
EventListener源代码
|
|
EventSource源代码
|
|
EventManagement源代码
|
|
ClientMain源代码
|
|
执行ClientMain类后的结果类似如下:
监听器:ClientMain$HelloWorldListener@64c3c749接收到事件,事件类型是:read, 事件附带的数据:this is a read event
监听器:ClientMain$SimpleListener@6bbc4459接收到事件,事件类型是:write, 事件附带的数据:this is a write event