我目前面临一个难题:将2个javascript对象连接在一起的正确方法是什么?
想象一下像文本编辑器这样的应用程序,它有几个不同的文件。我有一些HTML页面代表笔记本的视图。我有一个文件notebook.js,其中包含NotebookController和Notebook View的类定义。
NotebookControler对象负责在笔记本上执行业务逻辑,如“保存笔记本”,“加载笔记本”,“新笔记本”。 NotebookView负责管理用于演示的HTML。它做低级别的东西,如“获取/设置笔记本电脑主体”“获取/设置笔记本名称”。它还侦听DOM事件(onClick)并触发业务事件(saveNotebook)。这是我对被动视图模式的尝试。
我希望我的javascript客户端代码是面向对象的,分离的关注点和单元可测试的。我想用模拟NotebookView测试NotebookController,反之亦然。这意味着我不能只在NotebookController中实例化NotebookView。我也是
在Java中,选择是自然的:使用Spring。但这似乎不是JavaScript-y。什么是正确的做法?
答案 0 :(得分:3)
依赖注入可能是你最好的选择。与Java相比,JS代码中的某些方面更容易实现,因为您可以将一个充满回调的对象传递到NotebookController中。其他方面更难,因为您没有静态代码分析来形式化它们之间的接口。
答案 1 :(得分:3)
感谢您的见解。我最终编写了一个简单的JavaScript依赖注入实用程序。经过一段时间的辩论和你的评论后,我发现DI确实是正确的答案,因为:
所以这是DI实用程序:
var Dependency = function(_name, _instance, _dependencyMap) {
this.name = _name;
this.instance = _instance;
this.dependencyMap = _dependencyMap;
}
Dependency.prototype.toString = function() {
return this.name;
}
CONCORD.dependencyinjection = {};
CONCORD.dependencyinjection.Context = function() {
this.registry = {};
}
CONCORD.dependencyinjection.Context.prototype = {
register : function(name, instance, dependencyMap) {
this.registry[name] = new Dependency(name, instance, dependencyMap);
},
get : function(name) {
var dependency = this.registry[name];
return dependency != null ? dependency.instance : null;
},
init : function() {
YAHOO.log("Initializing Dependency Injection","info","CONCORD.dependencyinjection.Context");
var registryKey;
var dependencyKey;
var dependency;
var afterDependenciesSet = [];
for (registryKey in this.registry) {
dependency = this.registry[registryKey];
YAHOO.log("Initializing " + dependency.name,"debug","CONCORD.dependencyinjection.Context");
for(dependencyKey in dependency.dependencyMap) {
var name = dependency.dependencyMap[dependencyKey];
var instance = this.get(name);
if(instance == null) {
throw "Unsatisfied Dependency: "+dependency+"."+dependencyKey+" could not find instance for "+name;
}
dependency.instance[dependencyKey] = instance;
}
if(typeof dependency.instance['afterDependenciesSet'] != 'undefined') {
afterDependenciesSet.push(dependency);
}
}
var i;
for(i = 0; i < afterDependenciesSet.length; i++) {
afterDependenciesSet[i].instance.afterDependenciesSet();
}
}
}
答案 2 :(得分:2)
我会说,只需将它们连接在一起:
function wireTogether() {
var v = new View();
var c = new Controller();
c.setView(v);
}
但当然另一个问题提出了 - 你如何测试wireTogether()函数?
幸运的是,JavaScript是一种非常动态的语言,因此您只需为View和Controller分配新值:
var ok = false;
View.prototype.isOurMock = true;
Controller.prototype.setView = function(v) {
ok = v.isOurMock;
}
wireTogether();
alert( ok ? "Test passed" : "Test failed" );
答案 3 :(得分:1)
答案 4 :(得分:1)
还有一个JavaScript依赖注入框架:https://github.com/briancavalier/wire
答案 5 :(得分:0)
我会尝试对此进行尝试,但如果没有看到任何实际代码,那将会有点困难。就个人而言,我从未见过有人在(M)VC上使用JavaScript或IoC做过这样的特定尝试。
首先,你要测试什么?如果您还没有,请查看YUI Test video,其中包含有关使用javascript进行单元测试的一些信息。
其次,当你说“连接聚合的最佳方式”时,我可能会把它当作一个带控制器的二传手
// Production
var cont = new NotebookController();
cont.setView( new NotebookView() );
// Testing the View
var cont = new NotebookController();
cont.setView( new MockNotebookView() );
// Testing the Controller
var cont = new MockNotebookController();
cont.setView( new NotebookView() );
// Testing both
var cont = new MockNotebookController();
cont.setView( new MockNotebookView() );
但是,这对你如何设计控制器和查看对象有很大的假设。