在 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' });