Pull to refresh

Comments 12

Помимо внедрения зависимостей, библиотеки (dm.js не исключение) часто реализуют и другой вид инверсии управления, известный как паттерн Сервис Локатор. При таком подходе зависимости не только внедряются в сервис, но и сам сервис может запрашивать объекты у IoC контейнера, который выполняет роль локатора сервисов.

Простыми словами мы заменяем зависимость от конкретных сервисов на зависимость от Сервис Локатора. При этом он сам по себе должен быть легко переносимым.
Однако, в контексте веб-разработки в браузере, использовать паттерн Сервис Локатор в целях оптимизации оправданно — ведь далеко не всегда нужно загружать сразу все сервисы приложения и грузить тем самым много килобайт кода.

Но тогда нам придется инициализацию каждого плагина привязать к Сервис Локатору, хотя вызываемые у него сервисы могут быть использованы лишь несколькими методами плагина, а они могут не использоваться в данном приложении. И получается, что обязательная зависимость от Локатора для идеального плагина — лишняя.
Но если мы пользуемся всегда одним фреймворком/архитектурой — это не проблема, Локатор всегда при нас. А с разным архитектурами возникнет и проблема зависимости от конкретных сервисов.

Есть еще комбинированный вариант:
1. Плагин знает только о конкретных сервисах.
2. А вот инициализация плагина происходит при помощи Сервис Локатора. В данном конкретном приложении подключаем к плагину только нужные сервисы.
var locator, mapService, serviceLocator;
//Создаем Сервис Локатор
serviceLocator = new ServiceLocator();


// Создадим Картографа
mapService = new MapService({
    token: "my-application-token"
});

// Создадим Локатор
locator = new Locator();

// Вндерим зависимость Локатора при помощи Сервис Локатора
locator.setMapService(serviceLocator.getMapService());

// Вызовем метод локации
locator.locateUsers(users);

Таким образом, плагин становится чище, а централизованность обращения к сервисам сохранится.
Простыми словами мы заменяем зависимость от конкретных сервисов на зависимость от Сервис Локатора. При этом он сам по себе должен быть легко переносимым.


Не совсем так. Зависимость от сервисов все равно остается, при этом добавляется еще одна зависимость от Сервис Локатора.

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


Здесь немного не понял. Мы не привязываем инициализацию, мы делегируем создание объектов IoC контейнеру, вместо того, чтобы создавать объекты самим.
Можно просто взять AMD (require.js тот же), и имена модулей прописать константами (или в конфигурации require проставить).

Будет что-то типа:
var config = {
  logger: 'myApp/myLogger'
}

define('myApp/myModule', [config.logger], function(logger) { 
  ... 
})


Как по мне — это более JS-way: пользоваться гибкостью JS, а не тащить непонятные штуки из мира java enterprise.
В вашем примере вы инкапсулировали только реализацию логгера, но его создание и конфигурация лежит в ответственности модуля myModule. myModule должен знать о конфигурации логгера? Или в myApp/myLogger уже создается и конфигурируется экземпляр? ) Как можно поменять конфигурацию логгера?

Безусловно, использовать подобные паттерны или нет — решать вам. Более того, иногда они неоправданно усложняют разработку небольших приложений, которые не требуется поддерживать.

Однако, стоит помнить, что jQuery спагетти-код тоже совсем недавно считался «JS-way». =)
Как раз в методе инициализации require.js можно создать и реализовать что угодно, если это необходимо. В частности управлять версиями загруженных модулей и т.п. Это не DI, но все еще IoC. Далее работают сами синтаксические конструкции языка, где необходимо.

Что касается необходимости, то IoC с DI это еще тот антипаттерн в плане поддержки кода. JS и так ужасно поддерживается IDE по сравнению с .Net/Java. Молчу про то, что нет никаких способов нормально осуществлять Go to declaration нет, так еще и вводим паттерн, который намеренно усложняет эти связи. Представьте, что у вас пара сотен тысяч строк кода в проекте и как вы это будете поддерживать.
Согласен с тем, что, например AMD или CJS модули могут быть контейнерами сервисов. Но считаю, что это скорее побочный эффект оптимизаций загрузки, который использовать в архитектурных целях не очень правильно. Про синтаксические конструкции — можно подробнее? =)

Со вторым абзацем не согласен. На мой взгляд использование DI упрощает поддержку системы. «Go to declaration» поддерживается в CJS модулях, например Idea, а паттерн никак не влияет на связи в расположении классов.
Что-то сложно. Кажется, это слишком сложное решение, чтобы абстрагироваться от провайдеров карт — приходится думать больше над тем, как использовать этот dm, вместо того, как же подключить карту (непосредственно задача).
Вариант использовать веб-компонент, скажем,
<users-map provider="google"></users-map> 

выглядит в разы проще.
Этот-же компонент и из js элементарно вызывается new UsersMap({options});

Ведь есть-же чудесный xtags, polymer, или на худой конец их аналоги bosonic, mod.js. Сложно представить, что из подобных задач лучше решается в JS, чем через веб-компоненты.
Провайдеры карт — это лишь более наглядный пример. Представьте, что у вас есть сервис хранения кэшированных данных. И, например, две его имплементации — хранение в cookies, хранение в localStorage.

dm.get("cache").then(function(cacheService) {
    cacheService.store("my_key", {my_data: 1});
});


При этом можно сделать третью имплементацию, которая, в зависимости от браузера, будет определять, куда сохранять кэш. Такое можно реализовать на веб компонентах? На мой взгляд, это просто разные слои абстракций. В вашем примере вы передаете параметр provider, который означает, если я не ошибаюсь, что в компонент user-map содержит в себе все реализации провайдеров.

Более того, как быть со слоем DI в node.js?
Чем инверсия управления отличается от полиморфизма?
Странный вопрос. Инверсия управления, как принцип, в первую очередь, объектно-ориентированного программирования, безусловно включает в себя и понятие полиморфизм. Ровно, как и наследование и инкапсуляцию =)
Тогда, вообще, запутанно. Что там инвертируется и что управляется?)
Чтобы не играть в испорченный телефон, предлагаю прочитать материалы из ссылок в конце статьи, мне кажется, они лучше внесут ясность чем я в двух строках комментариев =)
Sign up to leave a comment.

Articles