Прочитав несколько статей на тему DI мне захотелось использовать его в Node.js; после недолгих поисков оказалось, что модулей для этого не так много, из них самый интересный — di.js от Angular, но он мне не подошел и я решил написать свой.
Почему не di.js?
- он написан с использованием ES6, т.е. нуждается в предварительной компиляции в ES5, а так как он использует декораторы, то и ваш код должен быть скомпилирован в ES5
- давно не поддерживается
- использует старый компилятор (es6-shim)
- нет возможности создавать несколько инстансов одного класса
Пишем свою реализацию
Самой интересной в написании модуля оказалась задача динамической передачи в конструктор аргументов.
Наиболее очевидное решение — использовать apply, но это не сработает, так как он взаимодействует с методами, а не конструкторами.
Для нашей цели можно воспользоваться spread operator:
class Test {
constructor(a, b) {
}
}
let args = [1, 2]
let test = new Test(...args)
В остальном реализация довольно скучна и не содержит ничего интересного.
Используем модуль
Я решил отказаться от декораторов di.js в пользу конфиг-файла. Допустим, мы описываем архитектуру компьютера, тогда в конфиге нам нужно описать наши классы, пути к ним и их аргументы:
{
"Computer": {
"class": "./Computer.js", // Путь к классу
"args": ["RAM", "HDD", "CPU", "GPU"] // Зависимости
},
"RAM": {
"class": "./RAM.js",
"args": []
},
"HDD": {
"class": "./HDD.js",
"args": []
},
"CPU": {
"class": "./CPU.js",
"args": ["RAM"]
},
"GPU": {
"class": "./GPU.js",
"args": []
}
}
Класс Computer, как и все остальные, довольно простой:
'use strict'
class Computer {
constructor(ram, hdd, cpu, gpu) {
this._cpu = cpu
this._gpu = gpu
this._hdd = hdd
this._ram = ram
}
}
module.exports = Computer
Теперь в точке входа нашего приложения используем модуль:
const Injector = require('razr')(__dirname, './path/to/your/config.json') // передаем текущий путь и путь к конфигу
const computer = Injector.get('Computer') // тут мы молучим инстанс Computer
Стоит заметить, что в конфиг-файле нужно указывать пути к классам относительно точки входа приложения.
На этом все. Спасибо всем, кто дочитал. А вот ссылочка на GitHub — https://github.com/Naltox/razr и NPM — http://npmjs.com/package/razr
Автор: Altox