1

将依赖项注入模型的最佳实践是什么?尤其是,如果他们的 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 的依赖项?

4

2 回答 2

6

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

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

在一种情况下,我无法使用 sinon 完全隔离 3rd 方代码,这是当 require() 模块执行某些您不想在测试中运行的行为时。对于这种情况,我制作了一个名为“mockrequire”的超级简单模块https://github.com/mateodelnorte/mockrequire,它允许您提供一个需要的内联模拟而不是实际模块。您可以提供一个使用来自 sinon 的 spy 或 stub 的模拟,并具有与所有其余测试相同的语法和模式。

希望这能回答您帖子中的基本问题。;)

于 2012-09-29T22:41:20.430 回答
2

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

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

例如

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 的函数体分开,并且通过使用一个类,您至少可以减少一点缩进的嵌套。

于 2012-09-29T12:29:38.650 回答