2009-03-06 3 views
16

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

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

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

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

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

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

+0

Может быть, я что-то отсутствует, но вы можете не достичь проверяемость, только убедившись, что вы используете агрегацию вместо композиции? –

+0

Это идея. Но действительно ли вопрос заключается в том, как правильно подключить эту агрегацию объектов? –

ответ

0

Я постараюсь сделать удар, но это будет немного сложно, если не увидеть никакого действительного кода. Лично я никогда не видел, чтобы кто-то делал такую ​​конкретную попытку (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()); 

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

2

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

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

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

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

var ok = false; 

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

wireTogether(); 

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

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

3

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

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

Так вот утилита 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(); 
     } 
    } 

} 
1

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

http://github.com/fschwiet/jsfioc

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

Смежные вопросы