将2个javascript对象连接在一起的正确方法是什么?

时间:2009-03-06 17:29:26

标签: javascript dependency-injection passive-view

我目前面临一个难题:将2个javascript对象连接在一起的正确方法是什么?

想象一下像文本编辑器这样的应用程序,它有几个不同的文件。我有一些HTML页面代表笔记本的视图。我有一个文件notebook.js,其中包含NotebookController和Notebook View的类定义。

NotebookControler对象负责在笔记本上执行业务逻辑,如“保存笔记本”,“加载笔记本”,“新笔记本”。 NotebookView负责管理用于演示的HTML。它做低级别的东西,如“获取/设置笔记本电脑主体”“获取/设置笔记本名称”。它还侦听DOM事件(onClick)并触发业务事件(saveNotebook)。这是我对被动视图模式的尝试。

我希望我的javascript客户端代码是面向对象的,分离的关注点和单元可测试的。我想用模拟NotebookView测试NotebookController,反之亦然。这意味着我不能只在NotebookController中实例化NotebookView。我也是

  • 在我的notebook.js中添加一些逻辑,将2连接在一起
  • 在我的应用程序中有一个全局函数,它知道要实例化其中一个并将它们连接在一起
  • 使用依赖注入,可以是本土的,也可以是SquirrelIoc

在Java中,选择是自然的:使用Spring。但这似乎不是JavaScript-y。什么是正确的做法?

6 个答案:

答案 0 :(得分:3)

依赖注入可能是你最好的选择。与Java相比,JS代码中的某些方面更容易实现,因为您可以将一个充满回调的对象传递到NotebookController中。其他方面更难,因为您没有静态代码分析来形式化它们之间的接口。

答案 1 :(得分:3)

感谢您的见解。我最终编写了一个简单的JavaScript依赖注入实用程序。经过一段时间的辩论和你的评论后,我发现DI确实是正确的答案,因为:

  1. 它完全将布线问题与业务逻辑分开,同时保持布线逻辑接近所连接的东西。
  2. 它允许我通常在我的对象上提供一个“你已经全部接线”回调,这样我就可以进行三阶段初始化:实例化所有内容,连接所有内容,调用每个人的回调并告诉他们他们已经连线
  3. 很容易检查依赖性缺失问题。
  4. 所以这是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() );

但是,这对你如何设计控制器和查看对象有很大的假设。