AngularJS: сервисы, фабрики, провайдеры

Чтоже это за странные service, factory и provider. Казалось бы - выполняют почти одну и туже функцию, подключаются через DI. Зачем их так много?

На абстрактный пример можно глянуть тут (к слову, автор привел очень хороший пример).

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

Сервис

Он чаще всего используется для создания разделяемого ресурса.

var constructor = function constructor() {  
 this.foo = 'foo'  
 this.bar = function bar() {

}  
}

.service('someService', constructor)

Когда сервис создается первый раз, то выполняется

var someServiceImpl = new constructor()

И в дальнейшем при подключении зависимостей через DI в объекты будет всегда передаваться someServiceImpl.

Фабрика
это более продвинутая конструкция. Она не является разделяемым ресурсом сама по себе. При каждом использовании фабрики через DI ее значение - это результат вызова фабричной функции.

var factoryFn = function () {  
 var someClass = function() {}

return someClass;  
}

.factory('someFactory', factoryFn)

При первом инстанцировании фабрики будет вызвана функция factoryFn и ее результат - это уже и есть разделяемое между всеми участниками системы значение.

Свое применения фабрика находит в первую очередь для реализации моделей. Как в примере выше. Создается и описывается класс модели someClass и фабрика при инстанцировании возвращает ссылку на него. В последующем можно использовать этот класс как конструктор объектов.

.controller('someController', ['someFactory', function(someFactory) {  
 // Тут мы успешно инстанцируем новый объект someClass  
 var someClassImpl = new someFactory();  
}])

Провайдер
Это тоже фабрика. Но более продвинутаця. Так же точно при первом инстанцировании провайдера выполняется некая функция и ее результат становится разделяемым значением.

Но вся мощь провайдеров в том, что их можно конфигурировать (в отличие от фабрик или сервисов). Т.е. на этапе инициализации вашего приложения можно передать провайдеру некоторые опции, которые нельзя указать в дальнейшем.

Как пример - библиотека для oauth-авторизации. на этапе конфигурирования в нее передаются токены.

var providerFn = function() {  
 var someModel = function() {  
 // это модель  
 }

this.configure = function() {  
 // делаем какую-то конфигурацию  
 }

this.$get = function() {  
 return new someModel()  
 }  
}

.provider('someProvider', providerFn)

И теперь самое интересное: при подключении провайдера через DI в качестве разделяемого объекта будет выступать то, что вернула функция $get.

В то же время на этапе конфигурирования нам доступен сам инстанс providerFn и мы можем использовать его функционал по конфигурированияю

.config(['someProvider', function(someProvider) {  
 //...  
 someProvider.configure(options)  
}])

Категории: Разработка