引子

在 Dependency Injection 中理解了相干概念,接下来看看在 Node 中如何应用依赖注入。

原文:Dependency Injection in Node.js

  • Origin
  • My GitHub

注释

依赖注入是一种软件设计模式,其中一个或多个依赖项(或服务)被注入或通过援用传递到依赖对象中。

应用依赖注入的理由

解耦

依赖注入使你的模块耦合性升高,从而产生更易于保护的代码库。

便于单元测试

你能够将它们传递到你想要应用的模块中,而不是应用硬编码的依赖项。在大多数状况下,你不用应用 proxyquire 这样的模块。

疾速开发

应用依赖注入,定义接口之后,就能够轻松地工作,不会呈现任何合并抵触。

如何应用 Node.js 依赖注入

首先,让咱们看看如何在不应用依赖注入的状况下编写你的应用程序,以及如何转换它。

没有应用依赖注入示例模块

// team.jsvar User = require('./user');function getTeam(teamId) {  return User.find({teamId: teamId});}module.exports.getTeam = getTeam;

一个简略的测试如下所示:

// team.spec.jsvar 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 办法,该办法返回一个用户列表。

看起来不错,对吧?但在测试时,咱们必须要应用测试存根。

在测试文件中,咱们还须要 require User 模型,这样就能够存根它的 find 办法。请留神,咱们在这里应用的是沙盒个性,因而不用在测试运行后手动复原原始函数。

应用依赖注入示例模块

// team.jsfunction 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.jsvar 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 中间件都应用雷同的办法。

Express 中间件

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 插件

同样的概念也能够在 Hapi 中找到-上面的示例将 handlebars 模块作为视图引擎注入 Hapi 中应用。

server.views({  engines: {    html: require('handlebars')  },  relativeTo: __dirname,  path: 'templates'});

参考资料

  • Dependency Injection in Node.js