Подтвердить что ты не робот

Инъекция зависимостей с RequireJS

Сколько я могу растянуть RequireJS для обеспечения инъекции зависимостей для моего приложения? В качестве примера предположим, что у меня есть модель, в которой я хочу быть синглом. Не один синглет в автономном синтаксисе getInstance() Single Single, но в синтаксисе с одним контекстом (один экземпляр на "контекст" ). Я хотел бы сделать что-то вроде...

require(['mymodel'], function(mymodel) {
   ...
}

И пусть mymodel является экземпляром класса MyModel. Если бы я сделал это в нескольких модулях, я бы хотел, чтобы mymodel был тем же, общим экземпляром.

Я успешно сделал эту работу, создав модуль mymodel следующим образом:

define(function() {
    var MyModel = function() {
        this.value = 10;
    }
    return new MyModel();
});

Является ли этот тип использования ожидаемым и распространенным, или я злоупотребляю RequireJS? Есть ли более подходящий способ выполнения инъекции зависимостей с RequireJS? Спасибо за вашу помощь. Все еще пытаюсь понять это.

4b9b3361

Ответ 1

На самом деле это не инъекция зависимостей, а место службы: ваши другие модули запрашивают "класс" с помощью строкового "ключа" и возвращают экземпляр, который "локатор обслуживания" (в данном случае RequireJS) имеет для подключения к ним.

Инъекция зависимостей включала бы возврат конструктора MyModel, т.е. return MyModel, а затем в центральный составной корень, вставляющий экземпляр MyModel в другие экземпляры. Я собрал образец того, как это работает здесь: https://gist.github.com/1274607 (также цитируется ниже)

Таким образом, корень композиции определяет, следует ли передавать один экземпляр MyModel (т.е. сделать его одноточечным) или новым для каждого класса, который требует его (экземпляр) или что-то среднее между ними. Эта логика не принадлежит ни к определению MyModel, ни к классам, которые запрашивают его экземпляр.

(Замечание: хотя я не использовал его, wire.js - это полноценный контейнер для инъекций зависимостей для JavaScript, который выглядит довольно круто.)


Вы не обязательно злоупотребляете RequireJS, используя его так же, как и вы, хотя то, что вы делаете, кажется немного окольным, то есть объявлением класса, чем возвратом его нового экземпляра. Почему бы просто не сделать следующее?

define(function () {
    var value = 10;

    return {
        doStuff: function () {
            alert(value);
        }
    };
});

Аналогия, которой вы, возможно, не хватает, состоит в том, что модули эквивалентны "пространствам имен" на большинстве других языков, хотя пространства имен, к которым вы можете присоединить функции и значения. (Это больше похоже на Python, чем на Java или С#.) Они не эквивалентны классам, хотя, как вы показали, вы можете сделать экспорт модулей равным тем, которые имеют данный экземпляр класса.

Итак, вы можете создавать синглтоны, присоединяя функции и значения непосредственно к модулю, но это похоже на создание синглета с использованием статического класса: он очень негибкий и, как правило, не лучший. Тем не менее, большинство людей рассматривают свои модули как "статические классы", потому что для правильной архивирования системы для инъекций зависимостей требуется много размышлений с самого начала, что на самом деле не является нормой в JavaScript.


Здесь https://gist.github.com/1274607 inline:

// EntryPoint.js
define(function () {
    return function EntryPoint(model1, model2) {
        // stuff
    };
});

// Model1.js
define(function () {
    return function Model1() {
        // stuff
    };
});

// Model2.js
define(function () {
    return function Model2(helper) {
        // stuff
    };
});

// Helper.js
define(function () {
    return function Helper() {
        // stuff
    };
});

// composition root, probably your main module
define(function (require) {
    var EntryPoint = require("./EntryPoint");
    var Model1 = require("./Model1");
    var Model2 = require("./Model2");
    var Helper = require("./Helper");

    var entryPoint = new EntryPoint(new Model1(), new Model2(new Helper()));
    entryPoint.start();
});

Ответ 2

Если вы серьезно относитесь к DI/IOC, вас может заинтересовать wire.js: https://github.com/cujojs/wire

Мы используем комбинацию переноса обслуживания (например, Domenic описывает, но используя curl.js вместо RequireJS) и DI (используя wire.js). Перемещение службы очень удобно при использовании макетных объектов в тестовых жгутах. DI является лучшим выбором для большинства других случаев использования.

Ответ 3

Не один синглет в самообслуживающем getInstance() - одноэлементном типе, но контекстно-зависимый синглтон (один экземпляр для "контекста" ).

Я бы рекомендовал его только для статических объектов. Совершенно нормально иметь статический объект в качестве модуля, который вы загружаете, используя блоки require/define. Затем вы создаете класс с только статическими свойствами и функциями. Затем у вас есть эквивалент Math Object, который имеет константы, такие как PI, E, SQRT и функции, такие как round(), random(), max(), min(). Отлично подходит для создания классов Utility, которые могут быть введены в любое время.

Вместо этого:

define(function() {
    var MyModel = function() {
        this.value = 10;
    }
    return new MyModel();
});

Что создает экземпляр, используйте шаблон для статического объекта (тот, где значения всегда совпадают с тем, что объект никогда не получает экземпляр):

define(function() {
    return {
       value: 10
    };
});

или

define(function() {
    var CONSTANT = 10;
    return {
       value: CONSTANT
    };
});

Если вы хотите передать экземпляр (результат использования модуля, который возвращает новый MyModel();), то в функции инициализации передайте переменную, которая фиксирует текущее состояние/контекст или передает объект, который содержит информацию о состоянии/контексте, о которых должны знать ваши модули.