假设我正在使用具有高度模块化代码的发布/订阅模式。当一个模块中的函数发出'发布'时,我如何确定其他模块中的哪些函数正在订阅该触发器?
例如:
// In module 1
function foo(data) {
publish("trigger", data);
}
// In module 2
function bar(data) {}
subscribe("trigger", bar);
// In module 3
function baz(data) {}
subscribe("trigger", baz);
在阅读模块1并看到已发出“发布”之后,有人会如何知道在我的代码中查找订阅的回调?
一个显而易见的解决方案可能是评论哪些模块包含订阅触发器的函数,但在处理大量发布/订阅者时这似乎是不切实际的解决方案。
我觉得我还没有完全理解如何使用pub / sub模式,因为对我来说,模式似乎没有任何关于函数链的透明度。
修改 的
我的问题涉及让我的代码清晰易读,以便有人阅读我的源代码。据我所知,在运行时,我可以通过访问存储的回调数组以编程方式查找存储订阅者列表。但这对于使我的原始源代码更容易理解没有任何作用。
例如,我目前使用这样的模式:
// Main Controller Module
function foo(data) {
module2.bar();
module3.bar();
}
// In module 2
function bar(data) {}
// In module 3
function baz(data) {}
对于初学者来说,这个模块的正确术语是什么?我认为这是一个'中介'模式,但是看here,看来调解员模式更像是我认为的酒吧/子模式?
使用这种模式,我觉得我的代码流是完全透明的。读者不需要四处寻找foo()可能调用的其他模块中的哪些函数。
但是使用pub / sub模式,一旦我从foo()发出发布,就像读者必须以某种方式找到订阅函数所在的模块。
但当然上述模式的缺点是严重依赖:模块1需要注入模块2和3才能调用bar()和baz()。
所以我想采用pub / sub模式的松散耦合,但我也想保持上面模式给我的函数流透明度。这可能吗?或者这只是一个pub / sub模式的固有权衡?
To Mod:
请删除问题。我写的这个问题很差,想以更清晰的方式重新提问。感谢。
答案 0 :(得分:1)
我认为发布订阅或调解器的整个想法是松散地耦合对象。 Object1不需要知道发生了什么会发生什么事只关心做自己的事情并通知谁有兴趣它做了它做的事情。
我只在控制器类中注册侦听器,而不是在整个代码中注册。当控制器需要添加或删除侦听器时,请先按步骤分解您的进程,以便首先通知控制器(为其创建适当的事件)。
例如:
在您的控制器中,您可以:
var Controller = {
//fetch information and display it
fetch : function(paramObj){
var subscribeIds = [];
//to have xhr listen to fetch can be done in an init function
// no need to add and remove every time but make a note here
// that it's registered in init and part of this process
subscribeIds.push(Mediator.subscribe(xhr.fetch,"fetch"));
//xhr will trigger dataFetched
subscribeIds.push(Mediator.subscribe(Controller.initProsessor,"dataFetched"));
//Controller will trigger displayFetched
subscribeIds.push(Mediator.subscribe(dom.displayFetched,"displayFetched"));
subscribeIds.push(Mediator.subscribe(Controller.displayedFetched,"displayedFetched"));
paramObj.suscribeIds = subsribeIds;
Mediator.trigger("fetch",paramObj);
},
initProsessor : function(paramObj){
var processor = Processor.make(paramObj.data.type);
paramObj.html = processor.process(data);
Mediator.trigger("displayFetched",paramObj);
},
displayedFetched : function(paramObj){
//You can decide the process is done here or take other steps
// based on paramObj
//You can unsubscribe listeners or leave them, when you leave them
// they should not be registered in the fetch function but rather
// in an init function of Controller with comments saying
// basic fetch procedure
Controller.cleanupListeners(paramObj.subscribeIds);
},
cleanupListeners : function(listenersIds){
Mediator.unSubscribe(listenersIds);
}
}
代码看起来比需要的更复杂。看着它的人可能会想为什么不让XHR制作一个Processor实例并告诉它进行处理?原因是Controller从字面上控制了应用程序的流程,如果你想在其中发生一些其他事情,你可以添加它们。随着应用程序的增长,您将添加越来越多的进程,有时会重新考虑函数以执行不太具体的操作,以便更好地重用它们。您现在只需在Controller中定义进程,而不必在几个文件中更改代码。
所以回答你关于在哪里找到听众以及在哪里注册事件的问题:在控制器中。
如果您有一个Mediator对象,您可以随时转储侦听器,只需编写一个dump方法,该方法将控制事件名称和函数.toString()。