这里不得不说《冒号课堂——编程范式与OOP思想》真是一本好书,之前已经看过一遍。这几天读Spring源码,发现Spring经常用到回调,对这个概念有些模糊了,于是把这本书翻出来看,算是温故知新。
事件驱动式模型
事件是程序中令人关注的信息状态上的变化。在基于事件驱动的系统中,事件包括内建事件与用户自定义事件,其中内建事件又分为底层事件和语义事件。此外,事件还有自然事件与合成事件之分。
上图是典型的事件驱动模型。事件处理器事先在关注的事件源上注册,事件源不定期地发表事件对象,经过事件管理器的转化(translate)、合并(coalesce)、排队(enqueue)、分派(dispatch)等集中处理后,事件处理器接收到事件并对其进行相应处理。事件处理器随时可以注册或注销事件源,意味着事件处理器和事件源之间的关系是动态建立和解除的。通过事件机制,事件源与事件处理器之间建立了松耦合的多对多关系:一个事件源可以有多个处理器,一个处理器可以监听多个事件源。再换个角度,把事件处理器视为服务方,事件源视为客户方,便是一个client-server 模式。每个服务方与其客户方之间的会话(session)是异步的,即在处理完一个客户的请求后不必等待下一请求,随时可切换(switch)到对其他客户的服务。更有甚者,事件处理器也能产生事件,实现处理器接口的事件源也能处理事件,它们可以角色换位,于是又演化为peer-to-peer模式。发行/订阅模式(publish-subscribe pattern)正是观察者模式(observer pattern)的别名,一方面可看作简化或退化的事件驱动式,另一方面可看作事件驱动式的核心思想。该模式省略了事件管理器部分,由事件源直接调用事件处理器的接口。这样更加简明易用,但威力有所削弱,缺少事件管理、事件连带等机制。著名的MVC(Model-View-Controller)架构正是它在架构设计上的一个应用。
回调
Callback指能作为参数传递的函数或代码,它允许低层模块调用高层模块,使调用者与被调者从代码上解耦。异步callback在传入后并不立即被调用,使调用者与被调者从时间上解耦。
控制反转一般通过callback来实现,其目的是降低模块之间的依赖性,从而降低模块的耦合度和复杂度。在框架设计中,控制反转增强了软件的可重用性、柔韧性和可扩展性,减少了用户的负担,简化了用户的代码。控制反转、依赖反转原则和依赖注射是近义词,它们的主题是控制与依赖,目的是解耦,方法是反转,而实现这一切的关键是抽象接口。