在Nodejs中具有依赖注入的模型

时间:2012-09-29 09:17:32

标签: node.js dependency-injection

将依赖项注入模型的最佳做法是什么?特别是,如果他们的getter是异步的,就像mongodb.getCollection()一样?

重点是用

注入一次依赖项
var model = require('./model')({dep1: foo, dep2: bar});

并调用所有成员方法,而不必将它们作为参数传递。我也不希望每个方法都以异步getter的瀑布开始。

我最终得到了一个专用的exports包装器,它代理所有调用并传递异步依赖项。

然而,这会产生很多开销,重复很多,我通常不喜欢它。

var Entity = require('./entity');

function findById(id, callback, collection) {
    // ...
    // callback(null, Entity(...));
};

module.exports = function(di) {
    function getCollection(callback) {
        di.database.collection('users', callback);
    };

    return {
        findById: function(id, callback) {
            getCollection(function(err, collection) {
                findById(id, callback, collection);
            });
        },
        // ... more methods, all expecting `collection`
    };
};

注入依赖项的最佳实践是什么,尤其是那些使用异步getter的方法?

2 个答案:

答案 0 :(得分:6)

如果你需要支持单元测试,那么像javascript这样的动态语言中的依赖注入可能比它的价值更麻烦。请注意,您需要的其他模块几乎不会使用您在Java,.NET和其他静态编译语言中看到的DI模式。

如果要模拟行为以隔离用于测试的特定代码单元,请参阅“sinon”模块http://sinonjs.org/。它允许您动态交换进/出拦截器,这些拦截器既可以监视方法调用,也可以完全替换它们。在实践中,您可以编写一个需要模块的mocha测试,然后需要在代码中使用的模块。使用sinon在该模块上监视或存根方法,因此,您可以隔离代码。

有一种情况我无法用sinon完全隔离第三方代码,这就是require()模块的行为执行某些你不想在测试中运行的行为。对于那种情况,我创建了一个名为“mockrequire”https://github.com/mateodelnorte/mockrequire的超级简单模块,它允许您提供内联模拟而不是实际模块。您可以提供一个使用来自sinon的间谍或存根的模拟,并且具有与所有其他测试相同的语法和模式。

希望这可以回答你帖子中的基本问题。 ;)

答案 1 :(得分:2)

在非常简单的情况下,您可以简单地导出一个修改文件范围内对象的函数并返回实际的导出对象,但是如果您想要更多地注入(即,从您的应用程序中多次使用),它就会#39 ;通常最好像你一样创建一个包装器对象。

通过使用包装类而不是返回对象的函数,可以在某些情况下减少一些开销和缩进。

例如

function findById(id, callback, collection) {
  // ...
  // callback(null, Entity(...));
};

function Wrapper(di) {
  this.di = di;
}
module.exports = Wrapper; // or do 'new' usage in a function if preferred

Wrapper.prototype.findById = function (id, callback) {
  // use this.di to call findById and getCollection
}, // etc

除此之外,你可以做很多改善的事情。我喜欢这种方法。保持状态di显式并与findById的函数体分开,并且通过使用类,您至少可以减少缩进的嵌套。