NodeJS:将依赖项作为函数参数注入或使用module.exports公开是否更好?

时间:2015-02-11 01:50:17

标签: node.js web-applications express dependency-injection circular-dependency

我有一个Web应用程序,当前调用require()时,我正在使用参数传递依赖项;像这样...

// Main app.js file

var express = require('express');
var mongoose = require('mongoose');
//config file for dev/production settings
var config = require('./config/');

//Set up App object etc.
var app = express();
var http = require('http').Server(app);
//Set up socket.io server & export as an app.publicMethod
var io = module.exports.io = require('socket.io')(http);
//Time Formatter exported so Jade can access
app.locals.moment = require('moment');

//Set up database using mongoose
var models = module.exports.models = require('./config/mongoose');

//Setup Operations (formerly controllers)
var operations = require('./controller')(app, models, io);

//Set up Routes (views & api)
var routes = require('./routes')(app, models, io, operations);

//Fire it up
var port = process.env.PORT || config.port;

http.listen(port, function() {
console.log('Started on port '+port);
  //Start any operations that need to wait for the server to start
  //operations.start();
});

特别是这一行

//Set up Routes (views & api)
var routes = require('./routes')(app, models, io, operations);

我最近需要从另一个独立脚本调用模型。所以我在这一行中公开了一个公共方法,允许我从另一个脚本中调用这个文件。

//Set up database using mongoose
var models = module.exports.models = require('./config/mongoose');

我不喜欢混合这些技术,因为随着应用程序的不断发展,它可能很快变得混乱并产生循环依赖。这是最好的方法吗?有没有更好的方法在我的脚本之间传递参数?

1 个答案:

答案 0 :(得分:1)

我在面向对象原则的SOLID的D中找到了我自己的答案。

Dependency Inversion Principle

首先,我必须意识到节点哲学本质上是模块化的。一切都应该总是有可能变成一个可以在更大的项目中使用的模块。

当我记住这个原则时,我意识到我们有一套简单的父子关系。每个脚本文件都是子依赖项的父项,或父项脚本的子项。当app.js之类的父文件调用其子文件时,它使用require('./routes');永远不会出现这样的情况,即将作为父对象的应用程序导出并包含在子脚本中。因为这留下了我喜欢称之为“voodoo链接”的东西,这种连接对于任何试图清理我的代码的传入程序员来说都是模糊的。存在循环依赖或更糟的危险。

所以我已经从我的app文件中禁用了module.exports,直到整个项目被打包并变成更大架构的模块依赖。这可以阻止app.js的子节点将其父节点作为依赖项调用。

相反,当我需要子脚本时,我可以使用依赖注入将参数传递给它,如var routes = require('./routes')(models, io); 这允许子脚本通过呈现用于执行其操作的有限变量集来保持其独立性。

有时我需要在子脚本中要求脚本。我喜欢将其视为侄女或侄子脚本。这就是诸如'routes.js'之类的脚本调用整个项目的模块依赖关系。但是,在项目的'app.js'父项中不应直接操作,而应将其作为依赖项注入。

//Child dependency of app.js (e.g. routes)
var twitter = require('twitter-npm-module');
module.exports = function (models, io) {
    ...
    twitter.scrape('some keyword');
};

关于我的最后一个问题,我希望从另一个脚本中调用模型,而不是在我的普通父/子树结构中。有三种选择。

  1. 将我的整个应用程序转换为此新脚本的依赖项。
  2. 将新脚本转换为app.js的子项,并使用上述技术注入依赖项。
  3. 创建一个完全独立的模块,该模块将作为单独的进程运行,并使用某种队列系统在两者之间传递消息。
  4. 我正在尝试使用rabbitmq选项3。