事件驱动与数据传递——消除事件传导带来的耦合

来源:互联网 发布:淘宝网,爱仕达炒锅 编辑:程序博客网 时间:2024/05/29 18:10

我发现事件驱动的编程中,有一个问题,就是数据的传递会造成功能的耦合。
举个例子:有两个模块A、B,如A的某功能需要从B处获取数据,那么用事件驱动的方式如下:
事件驱动传递数据

在A中,伪代码如下:

events.on('A.outerEvent', this.outerEvent);outerEvent() {    events.trigger('B.sendDataToA');}events.on('A.doSomethingByData', this.doSomethingByData);doSomethingByData(data) {    //use data here}

在B中,伪代码如下:

events.on('B.sendDataToA', this.sendDataToA);sendDataToA() {    events.trigger('A.doSomethingByData', this.data);}

这样B中就多了一个sendDataToA的事件,这个事件只负责将数据发送给A,而不能发送给其他模块。这样B与A就发生了耦合。

我们期望的方式应该是B中有一个方法,可以提供数据,不管哪个模块都可以取到,像下面这样(B中伪代码):

events.on('B.getData', this.getData);getData() {    return this.data;}

如果采用上面的方式,问题就变成为,A中的doSomethingByData事件由谁来触发呢?
要解决这个问题,我们不妨先打一个比方:假如A模块是一个餐厅服务员,B模块是顾客。现在老板让A为B服务点菜。下面这段对话将是我们日常生活中比较熟悉的了:

A:“欢迎光临,您想吃点什么?”
B:“给我来一份饺子,两瓣大蒜。”
A:“好的,我马上通知后厨给你做,您坐着稍等。”

然后B就坐在那玩手机等着吃饺子了,A开始通知后厨煮饺子、剥蒜……
很明显,A通知后厨做饭,这件事并不由B负责,B也不需要知道哪个是后厨,B有一切问题都会直接问A,在餐厅里,B只负责说出自己想吃什么(当然还包括付钱……),剩下的事就交给A了。

那么当我们把B点的菜看作是data,通知后厨做饭就是doSomethingByData,很显然A会等待B点完菜以后自己决定后续的工作,而不应该由B去指导怎么做。

也就是说A模块的业务代码应该全部保留在A中。那么基于事件驱动,A中该如何写呢?

//事件发送代码一去不回,不能满足获取数据的需求events.trigger('B.getData');

在这里我稍微给event代码增加了一个回调事件(而非回调函数)的功能,具体代码在这里:events.js in github
将一个事件触发后,取得的数据塞入另外一个由A指定的事件并触发,我将第二个事件命名为:eventInBag,图示如下:
events图示
那么A中代码就可以改为:

events.on('A.outerEvent', this.outerEvent);outerEvent() {    events.trigger({        event: 'B.getData',        eventInBag: 'A.doSomethingByData'    });}events.on('A.doSomethingByData', this.doSomethingByData);doSomethingByData(data) {    //use data here}

这样B模块就实现了与A模块的解藕。(完)