Прочитав несколько статей на тему 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