Node.js:导出类/原型与实例

min*_*gos 5 javascript dependency-injection testability node.js node-modules

当我用Java进行大多数编程时,我发现在Node.js模块而不是对象实例中导出类非常引人注目,例如:

class Connection {
    constructor(db) {
        this.db = db;
    }
    connect(connectionString) {
        this.db.connect(connectionString);
    }
}
exports.Connection = Connection;
Run Code Online (Sandbox Code Playgroud)

由于这样做需要跨相关模块多次实例化该类,因此我仍然需要导出一个已经存在的实例,以供其余生产代码使用。我在同一模块中执行此操作:

exports.connection = new Connection(require("mongoose"));
Run Code Online (Sandbox Code Playgroud)

这允许一些可测试性,因为可以在测试中交换真正的依赖项:

const Connection = require("./connection").Connection;

describe("Connection", () => {
    it("connects to a db", () => {
        const connection = new Connection({connect: () => {}});
        // ...
    });
});
Run Code Online (Sandbox Code Playgroud)

这种方法有效,但是当我在这里混合两种模式时却感觉很奇怪:导出原型(用于单元测试)和实例(用于生产代码)。这可以接受吗?我应该继续执行此操作还是更改为其他内容?如果是这样,首选模式是什么?

Dav*_*yan 0

你是对的,这是一种糟糕的编码风格,但实际上你可以编写一个函数,根据接收到的参数,返回单个实例(对于整个应用程序)或类本身(用于测试)。像这样的东西:

class MyClass() {}

const instance = new MyClass();

function getInstanceOrClass(isTesting) {
    if(isTesting) {
        return MyClass;
    } else {
        return instance;
    }
}

exports.getInstanceOrClass = getInstanceOrClass;

// in other files

const getInstanceOrClass = require('./yourFileName');

const classSingletonInstance = getInstanceOrClass();

// in test files

const getInstanceOrClass = require('./yourFileName');

const MyClass = getInstanceOrClass(true);
Run Code Online (Sandbox Code Playgroud)