Spec-Zone.ru › Angular.js 1.2

Улучшить эту документациюИнъекция зависимостей

Инъекция зависимостей (DI) — это шаблон проектирования программного обеспечения, который описывает, как компоненты получают свои зависимости.

Подсистема инжектора Angular отвечает за создание компонентов, разрешение их зависимостей и предоставление их другим компонентам по запросу.

Для углубленного обсуждения DI см. инъекцию зависимостей в Википедии, обратное управление Мартина Фаулера или прочитайте о DI в своей любимой книге по шаблонам проектирования программного обеспечения.

Инъекция зависимостей вкратце

Существует только три способа, которыми компонент (объект или функция) может получить свои зависимости:

  1. Компонент может создать зависимость, обычно используя оператор new.
  2. Компонент может найти зависимость, обратившись к глобальной переменной.
  3. Компонент может получить зависимость в качестве аргумента при необходимости.

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

Третий вариант наиболее жизнеспособен, поскольку он снимает с компонента ответственность за поиск зависимости. Зависимость просто передается компоненту.

function SomeClass(greeter) {
this.greeter = greeter;
}

SomeClass.prototype.doSomething = function(name) {
this.greeter.greet(name);
}

В приведенном выше примере SomeClass не беспокоится о создании или поиске зависимости greeter, а просто получает ее в момент создания greeter.

Это желательно, но ответственность за получение зависимости ложится на код, который создает SomeClass.

Для управления ответственностью за создание зависимостей каждое приложение Angular имеет инжектор injector. Инжектор — это локатор сервисов, ответственный за создание и поиск зависимостей.

Вот пример использования сервиса инжектора:

// Provide the wiring information in a module
var myModule = angular.module('myModule', []);

Обучите инжектор, как создать сервис greeter. Обратите внимание, что сервис greeter зависит от сервиса $window. Сервис greeter — это объект, содержащий метод greet.

myModule.factory('greeter', function($window) {
return {
  greet: function(text) {
    $window.alert(text);
  }
};
});

Создайте новый инжектор, который может предоставлять компоненты, определенные в нашем модуле myModule, и запросите от него сервис greeter (обычно это выполняется автоматически при запуске angular bootstrap).

var injector = angular.injector(['myModule', 'ng']);
var greeter = injector.get('greeter');

Запрос зависимостей решает проблему жесткой связи, но также означает, что инжектор необходимо передавать по всему приложению. Передача инжектора нарушает закон Деметера. Чтобы исправить это, мы используем декларативную запись в наших HTML-шаблонах, чтобы передать ответственность за создание компонентов инжектору, как в этом примере:

<div ng-controller="MyController">
<button ng-click="sayHello()">Hello</button>
</div>
function MyController($scope, greeter) {
$scope.sayHello = function() {
  greeter.greet('Hello World');
};
}

При компиляции Angular HTML обрабатывает директиву ng-controller, которая, в свою очередь, запрашивает у инжектора создание экземпляра контроллера и его зависимостей.

injector.instantiate(MyController);

Все это происходит за кулисами. Обратите внимание, что, попросив инжектор создать экземпляр класса, он может удовлетворить все зависимости MyController без того, чтобы контроллер когда-либо узнал об инжекторе.

Это наилучший результат. Код приложения просто объявляет необходимые зависимости, не взаимодействуя с инжектором. Эта настройка не нарушает закон Деметера.

Аннотация зависимостей

Как инжектор узнает, какие компоненты необходимо инжектировать?

Разработчик приложения должен предоставить информацию об аннотациях, которую инжектор использует для разрешения зависимостей. В Angular некоторые API-функции вызываются с использованием инжектора, как указано в документации API. Инжектору необходимо знать, какие сервисы инжектировать в функцию. Существует три эквивалентных способа аннотировать код с информацией о имени сервиса:

  • Неявным образом из имен параметров функции
  • Используя аннотацию свойства $inject
  • Используя аннотацию массива inline

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

Неявные зависимости

Самый простой способ получить зависимости — предположить, что имена параметров функции — это имена зависимостей.

function MyController($scope, greeter) {
// ...
}

Для функции инжектор может определить имена сервисов для инъекции, проанализировав объявление функции и извлекая имена параметров. В приведенном выше примере $scope и greeter — это два сервиса, которые необходимо инжектировать в функцию.

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

$inject Аннотация свойства

Чтобы позволить минификаторам переименовывать параметры функции и все же инжектировать нужные сервисы, функция должна быть аннотирована свойством $inject . Свойство $inject — это массив имен сервисов для инъекции.

var MyController = function(renamed$scope, renamedGreeter) {
...
}
MyController['$inject'] = ['$scope', 'greeter'];

В этом случае порядок значений в массиве $inject должен соответствовать порядку аргументов для инъекции. Используя приведенный выше фрагмент кода в качестве примера, $scope будет инжектирован в renamed$scope, а greeter в renamedGreeter. Следует позаботиться о том, чтобы аннотация $inject синхронизировалась с фактическими аргументами в объявлении функции.

Этот метод аннотации полезен для объявлений контроллеров, так как он присваивает информацию об аннотации самой функции.

Аннотация inline-массива

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

Например:

someModule.factory('greeter', function($window) {
// ...
});

Результатом является раздутый код из-за необходимости временной переменной:

var greeterFactory = function(renamed$window) {
// ...
};

greeterFactory.$inject = ['$window'];

someModule.factory('greeter', greeterFactory);

По этой причине предоставляется третий стиль аннотаций.

someModule.factory('greeter', ['$window', function(renamed$window) {
// ...
}]);

Здесь вместо простой передачи функции фабрики мы передаем массив, элементы которого содержат список строк (имена зависимостей) и саму функцию.

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

Где можно использовать DI?

DI широко используется в Angular. Вы можете использовать его при определении компонентов или при предоставлении блоков run и config для модуля.

  • Компоненты, такие как сервисы, директивы, фильтры и анимации, определяются инжектируемой функцией-фабрикой или конструктором. Эти компоненты могут быть инжектированы с компонентами «сервис» и «значение» в качестве зависимостей.

  • Метод run принимает функцию, которая может быть инжектирована с компонентами «сервис», «значение» и «константа» в качестве зависимостей. Обратите внимание, что вы не можете инжектировать «провайдеры» в блоки run.

  • Метод config принимает функцию, которая может быть инжектирована с компонентами «провайдер» и «константа» в качестве зависимостей. Обратите внимание, что вы не можете инжектировать компоненты «сервис» или «значение» в конфигурацию.

  • Контроллеры определяются конструктором, который может быть инжектирован любыми компонентами «сервис» и «значение» в качестве зависимостей, но им также могут быть предоставлены специальные зависимости. См. Контроллеры ниже для списка этих специальных зависимостей.

См. Модули для получения более подробной информации об инъекции зависимостей в блоки run и config.

Методы-фабрики

Методы-фабрики отвечают за создание большинства объектов в Angular. Примеры — директивы, сервисы и фильтры. Методы-фабрики регистрируются в модуле, и рекомендуемый способ объявления фабрик:

angular.module('myModule', [])
.factory('serviceId', ['depService', function(depService) {
  ...
}])
.directive('directiveName', ['depService', function(depService) {
  ...
}])
.filter('filterName', ['depService', function(depService) {
  ...
}]);

Методы модуля

Мы можем указать функции для выполнения во время конфигурации и выполнения модуля, вызвав методы run и config . Эти функции инжектируются с зависимостями, как и функции-фабрики выше.

angular.module('myModule', [])
.config(['depProvider', function(depProvider){
  ...
}])
.run(['depService', function(depService) {
  ...
}]);

Контроллеры

Контроллеры — это «классы» или «конструкторы функций», которые отвечают за предоставление функциональности приложения, которая поддерживает декларативную разметку в шаблоне. Рекомендуемый способ объявления контроллеров — использование записи с массивами:

someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
...
$scope.aMethod = function() {
  ...
}
...
}]);

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

Контроллеры являются особым случаем, так как в отличие от сервисов, может быть несколько экземпляров контроллеров в приложении. Например, будет по одному экземпляру для каждой директивы ng-controller в шаблоне.

Кроме того, для контроллеров доступны дополнительные зависимости:

  • $scope: Контроллеры всегда связаны с точкой в DOM и поэтому имеют доступ к scope в этой точке. Другие компоненты, такие как сервисы, имеют доступ только к синглтону $rootScope сервису.
  • $route разрешение: Если контроллер создается как часть маршрута, все значения, разрешенные в рамках маршрута, предоставляются для инъекции в контроллер.

© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.2.32/docs/guide/di

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API