Добро пожаловать в четвертую часть этой серии обзоров курса Pluralsight Основы Аурелии Брайана Нойеса.

Брайан является техническим директором и архитектором в Solliance, экспертной компании по разработке технологических решений.

Брайан — региональный директор Microsoft и MVP, он специализируется на многофункциональных клиентских технологиях, а также на создании поддерживающих их сервисов с помощью WCF и веб-API ASP.NET.

Вы можете следить за Брайаном через его блог на http://briannoyes.net.

Также в этой серии:

Часть 1 — Предварительные требования к Aurelia
Часть 2 — Начало работы
Часть 3 — Реализация MVVM

Назначение внедрения зависимостей и связанных с ним шаблонов

Внедрение зависимостей в основном связано с слабой связью между зависимыми компонентами.

Брайан также упоминает пару тесно связанных паттернов: Инверсия управления и Расположение службы.

Есть также много других курсов Pluralsight, посвященных внедрению зависимостей и/или инверсии управления.

Те, которые я видел и нашел полезными:

Интерфейсы C#, Джереми Кларк
Внедрение зависимостей RequireJS и загрузка модулей, Джефф Валоре
Создание модулей JavaScript с помощью Browserify, Джефф Валоре
Понимание ASP.NET Core, Роланд Гуйт
SOLID Principles of Object Oriented Design Стива Смита
Inversion of Control Джона Сонмеза
Practical IoC with ASP.NET MVC4 John Sonmez

Чтобы узнать больше о шаблоне Service Locator, см. Модуль Service Locator в курсе библиотеки шаблонов проектирования Джона Брауна.

Чтобы получить очень краткое изложение Service Locator, прочитайте эту статью в Википедии.

Также смотрите мою страницу Шаблоны дизайна.

Инверсия управления/внедрение зависимостей: проблема и решение

Брайан приводит пример:

  • Некоторый объект Consumer зависит от A
  • А зависит от В и С
  • B зависит от D
  • C зависит от D и E

Путь грубой силы для реализации этого состоит в том, чтобы обновить каждый объект перед его использованием, т.е. в A у нас будет new B(); и новый C(); и так далее. С этим есть две проблемы:

  1. Очень тесная связь между каждым компонентом
  2. Может быть общее состояние, и мы не можем использовать его, когда создаем отдельные экземпляры этого состояния.

Есть несколько возможных хакерских обходных путей, но Injection Dependency и Inversion of Control предлагают нам гораздо лучшее решение.

Брайан объясняет процесс, который проходит контейнер IoC в этом примере.

Использование декоратора «inject» в Aurelia

Шаблон:

  • импортировать необходимые модули
  • используйте декоратор @inject, передав сервис в качестве параметра

Я рекомендую прочитать статью Эдди Османи Изучаем декораторы ES7 и/или декораторы читайте меня Иегуды Каца, чтобы узнать больше о декораторах классов.

Брайан говорит здесь, что это функция ES2016. Это неправда, потому что в настоящее время они являются всего лишь предложением этапа 1 ES2017.

Он поддерживается TypeScript, подробнее об этом можно прочитать в Руководстве по TypeScript.

Брайан объясняет, что существует альтернативное решение, поддерживаемое Aurelia, которое представляет собой внедрение статического свойства с массивом имен типов.

статическая инъекция = [SomeService];

Внедрение зависимостей в действии

В этой демонстрации используется синтаксис декоратора класса для внедрения DataCache в конструкторы классов Event и Events.

Мы видим, что DataCache находится в общем состоянии, а режим внедрения зависимостей по умолчанию в Aurelia — singleton.

Декларативная регистрация жизненных экземпляров в Aurelia

Мы можем указать в классе, какое время жизни экземпляра должно быть в контейнере. Существует два основных шаблона:

  • Singleton — создается при первой инъекции, эта же ссылка передается в другие инъекции.
  • Transient — новый экземпляр создается для каждой инъекции

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

Использование декораторов Lifetime Management в Aurelia

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

Видим в логах консоли 3 отдельные конструкции DataCache

Явная регистрация типов и экземпляров в Aurelia

Есть три варианта:

  1. instance — просто создайте новый объект, затем зарегистрируйте его в контейнере
  2. синглтон
  3. преходящий

Для получения дополнительной информации см. Время жизни объекта, дочерние контейнеры и поведение по умолчанию

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

Эта демонстрация снова обновляет нашу функцию настройки, и мы видим, как реализовать каждую из трех опций, описанных в предыдущем уроке.

Использование резольверов в Aurelia

В настоящее время существует 4 готовых резолвера. Три из них описаны в этом уроке.

  • Lazy.of(T) — вводит функцию для ленивой оценки зависимости
  • All.of(T) — вводит массив всех сервисов, зарегистрированных с помощью предоставленного ключа.
  • Optional.of(T) — внедряет экземпляр класса, только если он уже существует в контейнере; ноль в противном случае.

См. Resolvers в официальной документации, чтобы узнать Parent.of(T)

Отложенная загрузка и создание экземпляров плагинов с помощью Aurelia

Сначала демонстрация использования Lazy.of(T).

Брайан создает класс ImLazy с конструктором и методом doStuff.

Затем создается файл events.js с классом Events и методом createAndUseImLazy.

В events.html есть кнопка, которая вызывает createAndUseImLazy.

Результатом всего этого является отсрочка построения зависимого объекта до момента, когда нам нужно его использовать.

Далее демонстрация All.of(T), полезная для плагинов. Мы можем захотеть зарегистрировать все плагины, связанные со сторонней системой.

Сначала нам нужно определение плагина. Мы видим класс PlugIn1 с методом doPlugInStuff и другой класс PlugIn2 с другим методом doPlugInStuff.

В main.js мы видим, как импортировать эти типы плагинов и регистрировать их как временные.

Наконец, мы добавляем All.of("SuperPlugIn") в наш класс Events.

Итак, у нас есть несколько экземпляров разных типов, зарегистрированных под одним и тем же именем «SuperPlugIn».

Регистрация глобальных зависимостей

Это отличный способ избежать повторяющихся импортных деклараций. Мы регистрируем зависимость глобально через метод настройки приложения.

Затем он будет доступен для внедрения в наши модули без оператора импорта и может использоваться в наших представлениях без элемента ‹require›.

Мы делаем это с помощью ключевого слова globalResources.

Для получения дополнительной информации см. Документацию FrameworkConfiguration.