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

Каков правильный способ соединения двух объектов javascript?

В настоящее время я сталкиваюсь с загадкой: как правильно подключить 2 объекта javascript?

Представьте себе приложение, такое как текстовый редактор с несколькими различными файлами. У меня есть HTML-страница, представляющая представление для ноутбука. У меня есть файл notebook.js, который содержит определения классов для NotebookController и Notebook View.

Объект NotebookControler, отвечающий за выполнение бизнес-логики на ноутбуке, например "Сохранить записную книжку", "Загрузить блокнот", "Новый ноутбук". NotebookView отвечает за управление HTML, который используется для презентации. Он делает вещи низкого уровня, такие как "получить/установить блокнот", "получить/установить название ноутбука". Он также прослушивает события DOM (onClick) и запускает бизнес-события (saveNotebook). Это моя попытка в пассивном представлении.

Я хочу, чтобы мой клиентский код javascript был объектно-ориентированным, разделенным интересам и проверяемым единицей. Я хочу протестировать NotebookController с макетным NotebookView и наоборот. Это означает, что я не могу просто создать экземпляр NotebookView внутри NotebookController. Так что я

  • Поместите некоторую логику в свой блокнот .js, который соединяет 2 вместе
  • У меня есть глобальная функция в моем приложении, которая знает, чтобы создать экземпляр одного из них и связать их вместе.
  • Используйте Injection Dependency, либо самодельный, либо что-то вроде SquirrelIoc

В Java выбор является естественным: используйте Spring. Но это не похоже на JavaScript-y. Какая правильная вещь?

4b9b3361

Ответ 1

Инъекционная инъекция, вероятно, лучше всего. По сравнению с Java, некоторые аспекты этого проще сделать в JS-коде, поскольку вы можете передать объект, полный обратных вызовов, в ваш NotebookController. Другие аспекты сложнее, потому что у вас нет статического анализа кода для формализации интерфейса между ними.

Ответ 2

Спасибо за понимание. Я закончил тем, что написал простую утилиту для загрузки зависимостей JavaScript. После долгого обсуждения и ваших комментариев, мне показалось, что DI действительно был правильным ответом, потому что:

  • Это полностью отделяет проблемы проводки от бизнес-логики, сохраняя логику проводки близко к проводным вещам.
  • Это позволило мне в общем случае обеспечить обратный вызов "вы все подключены" к моим объектам, чтобы я мог выполнить трехфазную инициализацию: создать экземпляр всего, подключить его все, вызвать все обратные вызовы и сообщить им, что они подключены.
  • Было легко проверить отсутствие проблем с ошибками.

Итак, здесь утилита DI:

var Dependency = function(_name, _instance, _dependencyMap) {
    this.name = _name;
    this.instance = _instance;
    this.dependencyMap = _dependencyMap;
}

Dependency.prototype.toString = function() {
    return this.name;
}

CONCORD.dependencyinjection = {};

CONCORD.dependencyinjection.Context = function() {
    this.registry = {};
}

CONCORD.dependencyinjection.Context.prototype = {
    register : function(name, instance, dependencyMap) {
        this.registry[name] = new Dependency(name, instance, dependencyMap);
    }, 
    get : function(name) {
        var dependency = this.registry[name];
        return dependency != null ? dependency.instance : null;
    },

    init : function() {
        YAHOO.log("Initializing Dependency Injection","info","CONCORD.dependencyinjection.Context");
        var registryKey;
        var dependencyKey;
        var dependency;
        var afterDependenciesSet = [];
        for (registryKey in this.registry) {
            dependency = this.registry[registryKey];
            YAHOO.log("Initializing " + dependency.name,"debug","CONCORD.dependencyinjection.Context");

            for(dependencyKey in dependency.dependencyMap) {
                var name = dependency.dependencyMap[dependencyKey];
                var instance = this.get(name);
                if(instance == null) {
                    throw "Unsatisfied Dependency: "+dependency+"."+dependencyKey+" could not find instance for "+name;
                }
                dependency.instance[dependencyKey] = instance; 
            }

            if(typeof dependency.instance['afterDependenciesSet'] != 'undefined') {
                afterDependenciesSet.push(dependency);
            }
        }

        var i;
        for(i = 0; i < afterDependenciesSet.length; i++) {
            afterDependenciesSet[i].instance.afterDependenciesSet();
        }
    }

}

Ответ 3

Я бы сказал, просто соедините их вместе:

function wireTogether() {
  var v = new View();
  var c = new Controller();
  c.setView(v);
}

Но тогда, конечно, возникает еще один вопрос - как вы проверяете функцию wireTogether()?

К счастью, JavaScript - действительно динамический язык, поэтому вы можете просто назначить новые значения View и Controller:

var ok = false;

View.prototype.isOurMock = true;
Controller.prototype.setView = function(v) {
  ok = v.isOurMock;
}

wireTogether();

alert( ok ? "Test passed" : "Test failed" );

Ответ 4

У меня есть инверсия библиотеки управления для javascript, я очень доволен ею. https://github.com/fschwiet/jsfioc. Он также поддерживает события, поэтому, если вы хотите, чтобы событие запуска было прекрасным. Он может использовать дополнительную документацию...

http://github.com/fschwiet/jsfioc

Другой (более новый?) вариант, который имеет лучшую документацию и поддержку, является requireJS (http://requirejs.org/).

Ответ 6

Я попытаюсь взять удар, но это будет немного сложно, если не увидеть какой-либо фактический код. Лично я никогда не видел, чтобы кто-то делал такую ​​конкретную попытку (M) VC с JavaScript или IoC, если на то пошло.

Прежде всего, с чем вы собираетесь протестировать? Если вы еще этого не сделали, проверьте YUI Test video, в котором есть хорошая информация об модульном тестировании с помощью javascript.

Во-вторых, когда вы говорите "лучший способ подключить эту агрегацию", я, вероятно, просто сделаю это как установщик с контроллером

// Production
var cont = new NotebookController();
cont.setView( new NotebookView() );

// Testing the View
var cont = new NotebookController();
cont.setView( new MockNotebookView() );

// Testing the Controller
var cont = new MockNotebookController();
cont.setView( new NotebookView() );

// Testing both
var cont = new MockNotebookController();
cont.setView( new MockNotebookView() );

Но это делает некоторое большое предположение о том, как вы уже разработали свой контроллер и просмотрите объекты.