Помощь с «Масштабируемой архитектурой приложений JavaScript»

#javascript #design-patterns #publish-subscribe

#javascript #шаблоны проектирования #опубликовать-подписаться

Вопрос:

Я создаю большое приложение на javascript и решил использовать проект масштабируемой архитектуры приложений Николаса Закаса: http://developer .yahoo.com/yui/theater/video.php?v=zakas-architecture

Согласно его системе, модули самоинкапсулируются и не знают друг о друге… Однако я сталкивался со многими примерами в моем проекте, когда казалось необходимым, чтобы модули знали друг о друге, потому что они, по сути, являются отдельными частями большего целого.

Например.. У меня есть три модуля: загрузка, окно и менеджер.

При нажатии на опцию загрузки открывается всплывающее окно с формой загрузки. Также ссылка находится в окне «менеджер».

При нажатии на ссылку manager всплывающее окно обновляется для отображения инструментов администрирования…

Для меня это имело наибольший смысл (псевдокод):

 upload module:
  upload option click --> sandbox.notification('need pop up window', [...html markup for form...])

manager module:
  manager link click --> sandbox.notification('need pop up window', [...html markup for admin tools...])

window module:
  sandbox.listen('need pop up window') --> calls createPopUpWindow( passed in html markup  )
  

… Однако это противоречит философии, потому что модули загрузки и диспетчера специально «запрашивают» модуль window что-то сделать, поэтому они знают об этом…

Итак, единственный другой способ, который я могу придумать для этого, был бы:

 upload module:
  upload option click --> sandbox.notification('upload option clicked', [...html markup for form...])

manager module:
  manager link click --> sandbox.notification('manager link clicked', [...html markup for admin tools...])

window module:
  sandbox.listen('upload option clicked') --> calls createPopUpWindow( passed in html markup  )
  sandbox.listen('manager link clicked') --> calls createPopUpWindow( passed in html markup  )
  

.. Но это кажется намного менее интуитивным, и, честно говоря, я думаю, что это делает мой код намного менее понятным, потому что просмотр уведомления модуля загрузки «выбран параметр загрузки» вообще не говорит мне, что это должно произойти при нажатии.. Я должен искать во всех моих других файлах модули, которые прослушивают это….. Что, я думаю, можно рассматривать как преимущество, потому что несколько модулей могут захотеть ответить на «выбран параметр загрузки», где «требуется всплывающее окно», очевидно, может быть адресовано только одному модулю.

Но при таком подходе для меня становится менее разумным, чтобы мой модуль загрузки передавал кучу html-разметки, относящейся к всплывающему окну, о котором он не знает, и начинает казаться, что модуль window должен отвечать за генерацию этой разметки — но большая часть разметки специфична для «загрузки», и в разметке есть прослушиватели событий, привязанные к функциям в модуле загрузки — так что наличие этого в модуле window не совсем логично … так что начинает становиться очень запутанным относительно того, что лучше способ структурировать все это.

У меня также есть другая ситуация, которая еще более проблематична.. Два модуля: трек и контейнер. Контейнер содержит много дорожек, и изначально у меня были только функции отслеживания, являющиеся внутренней частью модуля контейнера, но поскольку длина кода в модуле начала расти, я решил разделить их на отдельные модули ради чистоты кода… В любом случае, поскольку контейнеру необходимо знать о своих дорожках и иметь возможность ссылаться на них внутренне, единственный способ, которым я мог это настроить, — это сделать:

 containerObject = function(name) {
    this.name                       = name;
    this.video_track                = {'name': 'video',   'markup': sandbox.notification('create-track', 'video')}
    this.audio_track                = {'name': 'audio_1', 'markup': sandbox.notification('create-track', 'audio')}
    ....etc....
};
  

Итак, модуль Track выполняет изолированную среду.listen(‘create-track’) и указывает на это функции, которая возвращает новый объект track заданного типа….. Может быть, просто не стоит, чтобы track был его собственным модулем…… Поскольку это единственное место, где я присваиваю значение на основе вызова уведомления.

Я хотел бы услышать, что другие программисты, знакомые с архитектурой pub / sub, скажут по этой теме……

Пожалуйста, дайте мне свои мысли и советы.

Спасибо.

Комментарии:

1. Довольно простую реализацию, которая достаточно точно соответствует этому докладу, можно найти здесь: github.com/aranm/scalable-javascript-architecture

2. Возвращаюсь к этому старому сообщению, которое было очень полезным для меня в прошлом, чтобы дать ссылку на t3js , «минималистичный фреймворк JavaScript, который обеспечивает базовую структуру кода», созданный непосредственно Н. Закасом и его командой. Вот сообщение в блоге самого Закаса, в котором он представил это всего пару дней назад. Надеюсь, это тоже окажется полезным.

Ответ №1:

Существует ряд шаблонов, которые имеют дело с межобъектными коммуникациями — и это то, в чем заключается ваша настоящая проблема: коммуникация.

Ваша проблема может быть сведена к:

  1. Вы хотите, чтобы функциональные возможности были разбиты на модули
  2. Вы хотите, чтобы модули были как можно более автономными, с как можно меньшим количеством внешних ссылок
  3. Однако модули должны работать с другими модулями по «общей схеме вещей»

Номер 3 — это то, что вызывало у вас проблемы — вы хотите, чтобы модули были независимыми, но тогда им необходимо взаимодействовать с другими модулями, чтобы ваша программа работала.

Типичным решением для модуля будет открытие «стандартизированных» каналов связи с внешним миром. Не должно волновать (или иметь значение), сколько, какие, где или какие объекты находятся по другую сторону этих каналов. Он просто принимает команды из входных каналов и отправляет уведомления на выходные каналы. Замечательным побочным преимуществом является возможность простого модульного тестирования модуля.

Обратите внимание, что ваши модули не должны заботиться о другой стороне — четырех W

что — не должно волновать, с какими классами или объектами он взаимодействует (или прослушивает)

где — не должно волновать, где находится другая сторона (сервер? или в том же браузере)

для которого — не должно иметь значения, с каким конкретным объектом он взаимодействует (президент или просто работник)

сколько — не должно волновать, со сколькими объектами он разговаривает / прослушивает одновременно

Затем вы связываете весь график с основной конфигурацией. Это основная концепция внедрения зависимостей.

Что касается сантехники, есть несколько способов / шаблонов, с помощью которых это можно сделать:

  1. События и обработчики
  2. Опубликовать / подписаться
  3. Контейнер IOC / DI
  4. Комбинация вышеперечисленных