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

Последнее обновление: 1.11.2015

Внедрение зависимостей (Dependency Injection) представляет собой способ организации компонентов в приложении, при котором между компонентами отсутствуют жесткие связи: компоненты связаны посредством интерефейсов, а не конкретных реализаций. И в любое время мы можем динамически применить другую реализацию компонента.

В AngularJS ключевую роль во внедрении зависимостей играет сервис $injector. Его роль состоит в определении и установке зависимостей, которые используются функцией.

Свою функциональность сервис $injector реализует с помощью следующих методов:

  • annotate(fn): возвращает набор зависимостей для функции fn

  • get(name): возвращает контретную реализацию сервиса по определенному названию сервиса

  • has(name): возвращает true, если для указанного объекта name установлена зависимость

  • invoke(fn, self, locals): вызывает функцию fn. Может принимать два необязательных параметра: self (позволяет установить аргумент this для вызываемой функции) и locals (представляет альтернативный способ передачи аргументов в вызываемую функцию)

Рассмотрим на небольшом примере применение сервиса $injector:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>Dependency Injection</title>
<meta charset="utf-8" />
<link href="css/mystyles.css" rel="stylesheet" />
</head>
<body>
<div ng-controller="myController">
<button ng-click="buttonClick()">Не нажимать</button>
</div>
<script src="js/lib/angular.min.js"></script>
<script>
angular.module("myApp", []).controller("myController", function ($scope, $injector) {
	var counter = 0;
	var getData = function (dataService, message) {
		if (counter %2 == 0) {
			console.log(dataService.question);
		} 
		else {
			console.log(message);
		}
		counter++;
	}
	$scope.buttonClick = function () {
		var deps = $injector.annotate(getData);
		var args = [];
		for (var i = 0; i < deps.length; i++) {
			if ($injector.has(deps[i])) {
				args.push($injector.get(deps[i]));
				console.log("Сервис: " + deps[i]);
			} 
			else if (deps[i] == "message") {
				args.push("Привет мир");
				console.log("" + deps[i]);
			}
		}
		getData.apply(null, args);
	};
}).factory('dataService', function(){
    return{
        question:{
            text: 'Какой js-фреймворк лучше использовать?',
            author: 'Иван Иванов',
            date: '20/10/2013'
        }
    };
});
</script>
</body>
</html>

На странице определена кнопка, нажатие которой обрабатывается методом buttonClick(). Данный метод определен в контроллере MyController.

Чтобы задействовать сервис $injector, он передается в качестве параметра в функцию контроллер.

Кроме того, здесь определена функция getData, которая зависит от сервиса dataService, а также от аргумента message.

В методе buttonClick мы можем получить все используемые функцией getData зависимости с помощью выражения var deps = $injector.annotate(getData). После этого объект deps будет содержать набор используемых зависимостей, то есть dataService и message.

С помощью метода $injector.has(deps[i]) определяем, является ли зависимость зарегистрированным сервисом. Нам нет смысла как-то переопределять сервис dataService, а вот объект message мы можем определить какой угодно.

Затем с помощью метода $injector.get(deps[i]) получаем реализацию сервиса и добавляем в массив аргументов args

В конце вызываем метод с помощью стандартной функции javascript apply, передавая в нее полученные компоненты: getData.apply(null, args)

Теперь используем метод $injector.invoke(). Для этого изменим метод buttonClick():

$scope.buttonClick = function () {
	var locals = { message: "Привет Ир"};
	$injector.invoke(getData, null, locals);
};

Поскольку опять же нам нет смысла устанавливать зависимости для сервиса dataService, поэтому мы устанавливаем зависимости только для параметра message. Затем установленные параметры передаются в функцию $injector.invoke.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850