在 Dependency Injection 中了解了相关概念,接下来看看在 Node 中如何使用依赖注入。html
原文:Dependency Injection in Node.jsnode
依赖注入是一种软件设计模式,其中一个或多个依赖项(或服务)被注入或经过引用传递到依赖对象中。git
依赖注入使你的模块耦合性下降,从而产生更易于维护的代码库。github
你能够将它们传递到你想要使用的模块中,而不是使用硬编码的依赖项。在大多数状况下,你没必要使用 proxyquire 这样的模块。express
使用依赖注入,定义接口以后,就能够轻松地工做,不会出现任何合并冲突。npm
首先,让咱们看看如何在不使用依赖注入的状况下编写你的应用程序,以及如何转换它。设计模式
// team.js var User = require('./user'); function getTeam(teamId) { return User.find({teamId: teamId}); } module.exports.getTeam = getTeam;
一个简单的测试以下所示:api
// team.spec.js var Team = require('./team'); var User = require('./user'); describe('Team', function() { it('#getTeam', function* () { var users = [{id: 1, id: 2}]; this.sandbox.stub(User, 'find', function() { return Promise.resolve(users); }); var team = yield team.getTeam(); expect(team).to.eql(users); }); });
咱们在这里所作的是建立了一个名为 team.js
的文件,它能够返回属于单个团队的用户列表。为此,咱们须要 User
模型,所以咱们能够调用它的 find
方法,该方法返回一个用户列表。session
看起来不错,对吧?但在测试时,咱们必需要使用测试存根。app
在测试文件中,咱们还须要 require
User
模型,这样就能够存根它的 find
方法。请注意,咱们在这里使用的是沙盒特性,所以没必要在测试运行后手动恢复原始函数。
// team.js function Team(options) { this.options = options; } Team.prototype.getTeam = function(teamId) { return this.options.User.find({teamId: teamId}) } function create(options) { return new Team(options); }
你可使用如下测试用例测试此文件:
// team.spec.js var Team = require('./team'); describe('Team', function() { it('#getTeam', function* () { var users = [{id: 1, id: 2}]; var fakeUser = { find: function() { return Promise.resolve(users); } }; var team = Team.create({ User: fakeUser }); var team = yield team.getTeam(); expect(team).to.eql(users); }); });
好的,那么依赖注入的版本和上一个版本有何不一样呢?你能够注意到的第一件事是工厂模式的使用:咱们使用它向新建立的对象注入选项/依赖项—这是咱们能够注入 User
模型的地方。
在测试文件中,咱们必须建立一个表示 User
模型的假模型,而后咱们只需经过将其传递给 Team
模型的 create
函数来注入这个模型。很简单,对吧?
你能够在不少开源项目中找到依赖注入的例子。例如,你在平常工做中使用的大多数 Express/Koa 中间件都使用相同的方法。
var express = require('express'); var app = express(); var session = require('express-session'); app.use(session({ store: require('connect-session-knex')() }));
上面的代码片断使用工厂模式的依赖注入:向 session 中间件传递 connect-session-knex
模块-它必须实现一个接口,session
模块将调用该接口。
在这个示例中,connect-session-knex
模块必须实现如下方法:
store.destroy(sid, callback)
store.get(sid, callback)
store.set(sid, session, callback)
一样的概念也能够在 Hapi 中找到-下面的示例将 handlebars
模块做为视图引擎注入 Hapi 中使用。
server.views({ engines: { html: require('handlebars') }, relativeTo: __dirname, path: 'templates' });