Смущенный о Сервисе против Фабрики


618

Насколько я понимаю, когда я на фабрике, я возвращаю объект, который вводится в контроллер. Находясь внутри службы, я имею дело с объектом, использующим thisи не возвращающим ничего.

Я исходил из того, что служба всегда была одноэлементной , и что новый фабричный объект вводится в каждый контроллер. Однако, как выясняется, заводской объект тоже является синглтоном?

Пример кода для демонстрации:

var factories = angular.module('app.factories', []);
var app = angular.module('app',  ['ngResource', 'app.factories']);

factories.factory('User', function () {
  return {
    first: 'John',
    last: 'Doe'
  };
});

app.controller('ACtrl', function($scope, User) {
  $scope.user = User;
});

app.controller('BCtrl', function($scope, User) {
  $scope.user = User;
});

При изменении user.firstв ACtrlней получается, что user.firstв BCtrlтакже изменяется, например , Userодноэлементно?

Мое предположение было, что новый экземпляр был введен в контроллер с фабрикой?


4
Помимо «module.service» и «module.factory» есть еще 2 способа создания сервисов в AngularJS. Дополнительную информацию можно найти в сообщении в блоге: « Как создавать (одноэлементные) сервисы AngularJS четырьмя различными способами »
Эмиль ван Гален,

Возможный дубликат angular.service против angular.factory
Kaushal28

Ответы:


600

Все угловые услуги являются одиночными :

Документы (см. Раздел «Службы в виде синглтонов» ): https://docs.angularjs.org/guide/services.

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

В основном разница между сервисом и фабрикой заключается в следующем:

app.service('myService', function() {

  // service is just a constructor function
  // that will be called with 'new'

  this.sayHello = function(name) {
     return "Hi " + name + "!";
  };
});

app.factory('myFactory', function() {

  // factory returns an object
  // you can run some code before

  return {
    sayHello : function(name) {
      return "Hi " + name + "!";
    }
  }
});

Проверьте эту презентацию о $ обеспечить: http://slides.wesalvaro.com/20121113/#/

Эти слайды были использованы на одном из собраний AngularJ: http://blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html


13
См. Также stackoverflow.com/questions/15666048/…, где обсуждаются различия между обслуживанием, фабрикой и предоставлением.
Марк Райкок,

31
Официальный документ косвенно [так! не достаточно ясно] подразумевает, что даже если вы определяете сервис с фабрикой, он создается только один раз. Другими словами, он НЕ создается снова согласно ссылке (точке внедрения) - как бы вы это ни называли. Оба пути приводят к одному экземпляру на инжектор.
honzajde

3
Вы говорите: «сервис - это просто функция конструктора, которая будет вызываться с« новым »», но я думаю, что это вводит в заблуждение. Я не думаю, что это вызвано новым за кулисами, я думаю, что разработчик несет ответственность за вызов newэтого.
Тим Киндберг

5
@nfiniteloop, проверьте исходный код возле строки 3574. Фабрики - это метод $ get провайдера, а сервисы - это генерации фабрик, использующие метод, который вызывает $ injector.instantiate для предоставленной функции, которая затем вызывает new. ( См. Документы )
граждан

14
У меня сложилось впечатление, что сервис был таким же одноразовым, что вы использовали, получив ссылку на него. И что фабрика была единственным, который каждый раз возвращал новый объект. То есть сервис даст вам одну «машину», и все в вашем проекте будут использовать эту машину. В то время как фабрика будет давать вам новую машину каждый раз, когда вы вызываете фабрику. Один был синглтоном, который возвращал синглтон, а другой был синглтоном, который возвращал объект. Кто-нибудь может объяснить? Называть все как одиночный не помогает, так как это может относиться к нескольким вещам.
user2483724

380

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

Скажем, у нас есть:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

Разница между тремя заключается в том, что:

  1. aсохраненное значение приходит от запуска fn, другими словами:fn()
  2. bсохраненное значение приходит из newing fn, другими словами:new fn()
  3. cхранимое значение приходит с первого получения экземпляра с помощью newing fn, а затем запускает $getметод экземпляра

это означает, что внутри angular есть что-то вроде объекта кэша, значение которого для каждой инъекции присваивается только один раз, когда они были введены впервые, и где:

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

Вот почему мы используем thisв сервисах, а определяем this.$getв провайдерах.

Надеюсь это поможет.


54
наконец, вменяемое объяснение. Angular безумен и настолько ужасен, что причиняет боль.
Осирис

8
Это должен быть принятый ответ, поскольку он на самом деле отвечает на вопрос, ПОЧЕМУ фабрики, службы и поставщики возвращают единичные значения. Другие ответы объясняют разницу между фабриками, услугами и поставщиками, но никогда не касаются одноэлементного аспекта.
wmock

3
Мне нравится это ... Когда я читаю тысячи строк предложения от другого блоггера ... мне удается понять только фабрику. Но я читаю это ... я понимаю все 3.
Цохтан

@osiris Я согласен. Мне это не нравится Мне кажется, что он так сильно связан, что мои зубы скрипят.
Томас,

2
Таким образом, вы должны обеспечить реализацию $ get при использовании провайдеров?
Виктор

95

живой пример

пример "Привет, мир"

с factory/ service/ provider:

var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!"
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!"
        }
    };
});

//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {
    // In the provider function, you cannot inject any
    // service or factory. This can only be done at the
    // "$get" method.

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});


function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {

    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}​

57

Существует также способ вернуть функцию конструктора, чтобы вы могли возвращать новые классы на фабриках, например:

function MyObjectWithParam($rootScope, name) {
  this.$rootScope = $rootScope;
  this.name = name;
}
MyObjectWithParam.prototype.getText = function () {
  return this.name;
};

App.factory('MyObjectWithParam', function ($injector) {
  return function(name) { 
    return $injector.instantiate(MyObjectWithParam,{ name: name });
  };
}); 

Так что вы можете сделать это в контроллере, который использует MyObjectWithParam:

var obj = new MyObjectWithParam("hello"),

Смотрите здесь полный пример:
http://plnkr.co/edit/GKnhIN?p=preview

А вот страницы группы Google, где это обсуждалось:
https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ


У меня проблемы с минификацией на вашем примере. Вы знаете, как я должен аннотировать это?
Пол

2
Да, там существует сокращенная запись для Angular. Это должно быть что-то вроде этого: App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); Узнайте больше об этом здесь: docs.angularjs.org/tutorial/step_05
JustGoscha

4
зачем вам это делать, если вы можете использовать .serviceвместо этого?
флоп

у меня была та же мысль @flup. @justgoscha, есть ли какая-то польза ( воспринимаемая? ) от использования .factoryпо сравнению с .service?
xandercoded

5
Я думаю, потому что услуга является единой . То, что я построил здесь, это в основном класс, который является новым. Таким образом , вы можете иметь что - то вроде автосервиса завода , а затем сделать new Car('BMW')и new Car('Ford')они не разделяют одни и те же переменные и все.
JustGoscha

51

Вот основные отличия:

Сервисы

Синтаксис: module.service( 'serviceName', function );

Результат: при объявлении serviceName в качестве вводимого аргумента вам будет предоставлен экземпляр функции, переданной в module.service.

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

Заводы

Синтаксис: module.factory( 'factoryName', function );

Результат: при объявлении factoryName в качестве вводимого аргумента вам будет предоставлено значение, возвращаемое путем вызова ссылки на функцию, переданной в module.factory.

Использование: Может быть полезно для возврата функции 'class', которая затем может быть new'ed для создания экземпляров.

Также ознакомьтесь с документацией по AngularJS и схожим вопросам о стековом потоке, запутанном в отношении сервиса и фабрики .

Вот пример использования сервисов и фабрики . Узнайте больше о сервисе AngularJS vs factory .


6
Это имеет смысл для меня. Фабрика he возвращает план создания новых объектов.

27

В дополнение к первому ответу, я думаю, .service () предназначен для людей, которые написали свой код в более объектно-ориентированном стиле (C # / Java) (используя это ключевое слово и создавая объект с помощью функции prototype / Constructor).

Фабрика предназначена для разработчиков, которые пишут код, более естественный для javascript / функционального стиля кодирования.

Взгляните на исходный код метода .service и .factory внутри angular.js - внутренне все они вызывают метод провайдера:

  function provider(name, provider_) {
    if (isFunction(provider_)) {
      provider_ = providerInjector.instantiate(provider_);
    }
    if (!provider_.$get) {
      throw Error('Provider ' + name + ' must define $get factory method.');
    }
    return providerCache[name + providerSuffix] = provider_;
  }

  function factory(name, factoryFn) { \
    return provider(name, { $get: factoryFn }); 
  }

  function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

25

Очень просто:

.service - зарегистрированная функция будет вызываться как конструктор (также известный как newed)

.factory - зарегистрированная функция будет вызываться как простая функция

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


6
да. давайте не будем усложнять ситуацию, чем они есть на самом деле
провал

20

Все провайдеры работают одинаково. Различные методы service, factory,provider просто позволяют сделать то же самое в меньше кода.

PS Там же valueиconstant .

Каждый особый случай по цепочке, начиная с providerи заканчиваяvalue имеет дополнительное ограничение. Таким образом, чтобы решить между ними, вы должны спросить себя, что позволит вам выполнить то, что вы хотите, с меньшим количеством кода.

Вот картинка, которая показывает вам, что я имею в виду:

введите описание изображения здесь

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

http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


Службы называются одноэлементными, но почему они одноэлементные, если каждый раз, когда я внедряю их, создается новый экземпляр?
Анкур Марваха

1
@AnkurMarwaha Новый экземпляр создается не каждый раз, он создается только один раз и кэшируется AngularJS. Это верно, если вы используете провайдера, фабрику, сервис и т. Д. Вы можете подтвердить это, используя console.log()и вводя в несколько контроллеров.
Луис Перес

Луис, Ваш комментарий вступает в противоречие с принятым ответом, как говорится: «Наконец, важно понимать, что все сервисы Angular являются приложениями. Это означает, что существует только один экземпляр данной услуги для каждого инжектора.
Анкур Марваха

@ AnkurMarwaha, может быть, я что-то неправильно понимаю. Вы цитировали «важно понимать, что все сервисы Angular являются одиночными приложениями» - тот факт, что они являются одиночными, означает, что они создаются только один раз. Вот что я сказал: «Новый экземпляр создается не каждый раз, он создается только один раз и кэшируется ...». Можете ли вы указать более подробно, где вы видите конфликт?
Луис Перес

1
Ах, я вижу замешательство. «Инжектор» - это объект под углом. Он отвечает за выполнение «инъекций». Например, при первом запуске контроллера «инжектор» просматривает параметры и вводит каждый из них. Для всего вашего приложения есть только один «инжектор». Как только инжектор создает конкретную фабрику или службу, он сохраняет экземпляр и повторно использует его - отсюда и синглтон. Таким образом, существует только один инжектор для каждого приложения и только один экземпляр данной службы для каждого инжектора. У большинства приложений Angular есть только одно приложение, следовательно, один инжектор, следовательно, один экземпляр какого-либо сервиса, контроллера и т. Д.
Луис Перес

13

Вот еще несколько примеров услуг по сравнению с фабриками, которые могут быть полезны, чтобы увидеть разницу между ними. По сути, к сервису обращаются «new ...», он уже создан. Фабрика не создается автоматически.

Основные примеры

Вернуть объект класса, который имеет единственный метод

Вот сервис, который имеет единственный метод:

angular.service('Hello', function () {
  this.sayHello = function () { /* ... */ };
});

Вот фабрика, которая возвращает объект с методом:

angular.factory('ClassFactory', function () {
  return {
    sayHello: function () { /* ... */ }
  };
});

Вернуть значение

Фабрика, которая возвращает список чисел:

angular.factory('NumberListFactory', function () {
  return [1, 2, 3, 4, 5];
});

console.log(NumberListFactory);

Сервис, который возвращает список номеров:

angular.service('NumberLister', function () {
  this.numbers = [1, 2, 3, 4, 5];
});

console.log(NumberLister.numbers);

Вывод в обоих случаях одинаков, список номеров.

Расширенные примеры

Переменные класса с использованием фабрик

В этом примере мы определяем CounterFactory, он увеличивает или уменьшает счетчик, и вы можете получить текущий счетчик или узнать, сколько объектов CounterFactory было создано:

angular.factory('CounterFactory', function () {
  var number_of_counter_factories = 0; // class variable

  return function () {
    var count = 0; // instance variable
    number_of_counter_factories += 1; // increment the class variable

    // this method accesses the class variable
    this.getNumberOfCounterFactories = function () {
      return number_of_counter_factories;
    };

    this.inc = function () {
      count += 1;
    };
    this.dec = function () {
      count -= 1;
    };
    this.getCount = function () {
      return count;
    };
  }

})

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

var people_counter;
var places_counter;

people_counter = new CounterFactory();
console.log('people', people_counter.getCount());
people_counter.inc();
console.log('people', people_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());

places_counter = new CounterFactory();
console.log('places', places_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());
console.log('counters', places_counter.getNumberOfCounterFactories());

Выход этого кода:

people 0
people 1
counters 1
places 0
counters 2
counters 2

это полезный пример, number_of_counter_factories похож на мета-атрибут класса CounterFactory, верно? Я понимаю, что этот пример можно реплицировать на службу (скажите, если я ошибаюсь), какова будет семантическая разница в этом случае?
Geoom

Полезный пример! Таким образом, это в основном означает, что на фабрике у вас может быть тот дополнительный уровень абстракции, который бы не попал в сервис. Что бы ни возвращалось, новый экземпляр этого будет возвращаться всякий раз, когда используется «новый». Любые переменные, которые не объявлены внутри возвращаемого блока, будут одиночными. Я правильно понял?
Сванидхи

@Swanidhi в основном да, вы можете объявить переменные, которые являются синглетонами на фабрике. Вот почему я назвал их «классовыми» переменными.

13

«Фабрика» и «Сервис» - это разные способы выполнения DI (инжекция зависимости) в угловых.

Поэтому, когда мы определяем DI, используя «сервис», как показано в коде ниже. Это создает новый экземпляр GLOBAL объекта «Logger» и внедряет его в функцию.

app.service("Logger", Logger); // Injects a global object

Когда вы определяете DI, используя «фабрику», он не создает экземпляр. Он просто передает метод, и позже потребитель внутри должен сделать вызовы фабрике для экземпляров объекта.

app.factory("Customerfactory", CreateCustomer);

Ниже приведено простое изображение, которое наглядно показывает, как процесс DI для «Service» отличается от «Factory».

введите описание изображения здесь

Фабрика должна использоваться, когда мы хотим создавать различные типы объектов в зависимости от сценариев. Например, в зависимости от сценария мы хотим создать простой объект «Клиент» или «Клиент» с объектом «Адрес» или «Клиент» с объектом «Телефон». Вот подробное объяснение этого пункта

Служба должна использоваться, когда у нас есть служебные или общие функции, которые нужно внедрить, такие как Utility, Logger, Error handler и т. Д.


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

8

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

Сервис в AngularJS - это одноэлементный объект JavaScript, который содержит набор функций

var myModule = angular.module("myModule", []);

myModule.value  ("myValue"  , "12345");

function MyService(myValue) {
    this.doIt = function() {
        console.log("done: " + myValue;
    }
}

myModule.service("myService", MyService);
myModule.controller("MyController", function($scope, myService) {

    myService.doIt();

});

Фабричный стиль: ( более сложный, но более сложный ) возвращает возвращаемое значение функции: создать экземпляр объекта типа new Object () в java.

Фабрика - это функция, которая создает значения. Когда службе, контроллеру и т. Д. Требуется значение, введенное фабрикой, фабрика создает значение по требованию. После создания значение используется повторно для всех служб, контроллеров и т. Д., Которым оно необходимо ввести.

var myModule = angular.module("myModule", []);

myModule.value("numberValue", 999);

myModule.factory("myFactory", function(numberValue) {
    return "a value: " + numberValue;
})  
myModule.controller("MyController", function($scope, myFactory) {

    console.log(myFactory);

});

Стиль провайдера : ( полнофункциональная, конфигурируемая версия ) возвращает выходные данные функции $ get функции: Configurable.

Поставщики в AngularJS - это самая гибкая форма фабрики, которую вы можете создать. Вы регистрируете провайдера в модуле так же, как в сервисе или на фабрике, за исключением того, что вы используете вместо него функцию provider ().

var myModule = angular.module("myModule", []);

myModule.provider("mySecondService", function() {
    var provider = {};
    var config   = { configParam : "default" };

    provider.doConfig = function(configParam) {
        config.configParam = configParam;
    }

    provider.$get = function() {
        var service = {};

        service.doService = function() {
            console.log("mySecondService: " + config.configParam);
        }

        return service;
    }

    return provider;
});

myModule.config( function( mySecondServiceProvider ) {
    mySecondServiceProvider.doConfig("new config param");
});

myModule.controller("MyController", function($scope, mySecondService) {

    $scope.whenButtonClicked = function() {
        mySecondService.doIt();
    }

});

src jenkov

<!DOCTYPE html>
    <html ng-app="app">
    <head>
    	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
    	<meta charset=utf-8 />
    	<title>JS Bin</title>
    </head>
    <body ng-controller="MyCtrl">
    	{{serviceOutput}}
    	<br/><br/>
    	{{factoryOutput}}
    	<br/><br/>
    	{{providerOutput}}
    
    	<script>
    
    		var app = angular.module( 'app', [] );
    
    		var MyFunc = function() {
    
    			this.name = "default name";
    
    			this.$get = function() {
    				this.name = "new name"
    				return "Hello from MyFunc.$get(). this.name = " + this.name;
    			};
    
    			return "Hello from MyFunc(). this.name = " + this.name;
    		};
    
    		// returns the actual function
    		app.service( 'myService', MyFunc );
    
    		// returns the function's return value
    		app.factory( 'myFactory', MyFunc );
    
    		// returns the output of the function's $get function
    		app.provider( 'myProv', MyFunc );
    
    		function MyCtrl( $scope, myService, myFactory, myProv ) {
    
    			$scope.serviceOutput = "myService = " + myService;
    			$scope.factoryOutput = "myFactory = " + myFactory;
    			$scope.providerOutput = "myProvider = " + myProv;
    
    		}
    
    	</script>
    
    </body>
    </html>

jsbin

<!DOCTYPE html>
<html ng-app="myApp">
<head>
	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
	<meta charset=utf-8 />
	<title>JS Bin</title>
</head>
<body>
<div ng-controller="MyCtrl">
    {{hellos}}
</div>
	<script>

	var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!"
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!"
        }
    };
});
    
//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});
        

function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
    
    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}
	</script>

</body>
</html>

jsfiddle


2

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

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

Или, кратко говоря, « поставщик - это более общая форма, в то время как сервис ограничен только объектами».


2

Вот как я понял разницу между ними с точки зрения шаблонов проектирования:

Сервис : вернуть тип, который будет обновлен для создания объекта этого типа. Если используется аналогия с Java, Service возвращает определение класса Java .

Фабрика : возвращает конкретный объект, который можно сразу использовать. В аналогии с Java фабрика возвращает объект Java .

Часть, которая часто смущает людей (в том числе и меня), заключается в том, что когда вы внедряете Сервис или Фабрику в свой код, они могут использоваться одинаково, то, что вы получаете в своем коде в обоих случаях, является конкретным объектом, который вы можете немедленно вызвать. Что означает в случае Сервиса, угловые звонки «новые» в декларации сервиса от вашего имени. Я думаю, что это замысловатая концепция.


1

Это был бы лучший и краткий ответ для понимания Service Vs Factory Vs Provider

Источник : https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/HuZsOsMvKv4J

Вот что Бен говорит с демонстрацией http://jsbin.com/ohamub/1/edit?html,output

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

Сервисы

Синтаксис : module.service ('serviceName', функция);

Результат : при объявлении serviceName в качестве вводимого аргумента вам будет предоставлена ​​фактическая ссылка на функцию, переданная в module.service.

Использование : Может быть полезно для совместного использования служебных функций, которые полезно вызывать, просто добавляя () к введенной ссылке на функцию. Также может быть запущен с injectedArg.call (this) или аналогичным.

Заводы

Синтаксис : module.factory ('factoryName', функция);

Результат : при объявлении factoryName в качестве вводимого аргумента вам будет предоставлено значение, возвращаемое путем вызова ссылки на функцию, переданной в module.factory.

Использование : Может быть полезно для возврата функции 'class', которая затем может быть new'ed для создания экземпляров.

Провайдеры

Синтаксис : module.provider ('providerName', функция);

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

Использование : Может быть полезно для возврата функции 'class', которая затем может быть добавлена ​​new для создания экземпляров, но которая требует некоторой конфигурации перед внедрением. Возможно, полезно для классов, которые можно использовать в разных проектах? Все еще немного смутно на этом. "Бен


1

У меня было некоторое замешательство, и я изо всех сил стараюсь дать простое объяснение здесь. Надеюсь, это поможет!

angular .factoryи angular .serviceоба используются для инициализации службы и работают одинаково.

Разница лишь в том, как вы хотите инициализировать свой сервис.

Оба синглтоны


var app = angular.module('app', []);


завод

app.factory ( <service name>, <function with a return value>)

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

например

function myService() {
  //return what you want
  var service = {
    myfunc: function (param) { /* do stuff */ }
  }
  return service;
}

app.factory('myService', myService);

При введении этой услуги (например, вашему контроллеру):

  • Угловой будет называть вашу данную функцию (как myService()) , чтобы вернуть объект
  • Singleton - вызывается только один раз, сохраняется и передает один и тот же объект.


обслуживание

app.service ( <service name>, <constructor function>)

Если вы хотите инициализировать свой сервис из функции конструктора (используя thisключевое слово), вы должны использовать этот serviceметод.

например

function myService() {
  this.myfunc: function (param) { /* do stuff */ }
}

app.service('myService', myService);

При введении этой услуги (например, вашему контроллеру):

  • Angular будет использовать newзаданную функцию (как new myService()) для возврата объекта
  • Singleton - вызывается только один раз, сохраняется и передает один и тот же объект.


ПРИМЕЧАНИЕ: если вы используете factoryс <constructor function>или serviceс <function with a return value>, это не будет работать.


Примеры - ДЕМО


1

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

Служба - это метод в модуле, который принимает имя, и функция, которая определяет службу. Вы можете внедрить и использовать этот конкретный сервис в других компонентах, таких как контроллеры, директивы и фильтры. Фабрика - это метод в модуле, который также принимает имя и функцию, которые определяют фабрику. Мы также можем внедрить и использовать его так же, как мы это сделали с сервисом.

Объекты, созданные с помощью new, используют значение свойства prototype их функции конструктора в качестве своего прототипа, поэтому я обнаружил код Angular, который вызывает Object.create (), который, как я считаю, является функцией конструктора службы, когда она создается. Однако фабричная функция - это на самом деле просто вызываемая функция, поэтому мы должны возвращать литерал объекта для фабрики.

Вот угловой код 1.5, который я нашел для фабрики:

var needsRecurse = false;
    var destination = copyType(source);

    if (destination === undefined) {
      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
      needsRecurse = true;
    }

Фрагмент углового исходного кода для функции factory ():

 function factory(name, factoryFn, enforce) {
    return provider(name, {
      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
    });
  }

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

Вот угловой код 1.5 для обслуживания.

function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

Оказывается, когда мы вызываем service (), он на самом деле вызывает factory ()! Тем не менее, он не просто передает нашу функцию конструктора сервиса на завод. Он также передает функцию, которая просит инжектор создать объект с помощью данного конструктора.

Другими словами, если мы внедряем MyService где-то, что происходит в коде:

MyServiceProvider.$get(); // return the instance of the service

Чтобы повторить это снова, сервис вызывает фабрику, которая является методом $ get () соответствующего провайдера. Более того, $ injector.instantiate () - это метод, который в конечном итоге вызывает Object.create () с функцией конструктора. Вот почему мы используем «это» в сервисах.

Для ES5 не имеет значения, какой мы используем: service () или factory (), всегда вызывается фабрика, которая создает провайдера для нашего сервиса.

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

Почему большинство людей рекомендуют использовать фабрики вместо услуг? Это лучший ответ, который я когда-либо видел, из книги Павла Козловского: освоение разработки веб-приложений с помощью AngularJS.

Фабричный метод является наиболее распространенным способом получения объектов в систему внедрения зависимостей AngularJS. Он очень гибкий и может содержать сложную логику создания. Поскольку фабрики являются регулярными функциями, мы также можем воспользоваться новой лексической областью для моделирования «частных» переменных. Это очень полезно, так как мы можем скрыть детали реализации данного сервиса. "


1
  • С фабрикой вы фактически создаете объект внутри фабрики и возвращаете его.
  • С сервисом у вас просто есть стандартная функция, которая использует thisключевое слово для определения функции.
  • С провайдером есть $getвы определяете , и он может быть использован , чтобы получить объект , который возвращает данные.

1

В AngularJS есть три способа работы с бизнес-логикой: ( Вдохновленный курсом Яакова Coursera AngularJS ):

  1. обслуживание
  2. завод
  3. поставщик

Здесь мы будем только говорить о Service vs Factory

СЕРВИС :

Синтаксис:

app.js

 var app = angular.module('ServiceExample',[]);
 var serviceExampleController =
              app.controller('ServiceExampleController', ServiceExampleController);
 var serviceExample = app.service('NameOfTheService', NameOfTheService);

 ServiceExampleController.$inject = ['NameOfTheService'] //very important as this protects from minification of js files

function ServiceExampleController(NameOfTheService){
     serviceExampleController = this;
     serviceExampleController.data = NameOfTheService.getSomeData();
 }

function NameOfTheService(){
     nameOfTheService = this;
     nameOfTheService.data = "Some Data";
     nameOfTheService.getSomeData = function(){
           return nameOfTheService.data;
     }     
}

index.html

<div ng-controller = "ServiceExampleController as serviceExample">
   {{serviceExample.data}}
</div>

Основные особенности Сервиса:

  1. Lazily Instantiated : если сервис не внедрен, он никогда не будет создан. Таким образом, чтобы использовать его, вам придется ввести его в модуль.

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

ФАБРИКА

Теперь поговорим о фабрике в AngularJS

Сначала давайте посмотрим на синтаксис :

app.js :

var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);

//first implementation where it returns a function
function NameOfTheFactoryOne(){
   var factory = function(){
      return new SomeService();
    }
   return factory;
}

//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
   var factory = {
      getSomeService : function(){
          return new SomeService();
       }
    };
   return factory;
}

Теперь с помощью двух выше в контроллере:

 var factoryOne = NameOfTheFactoryOne() //since it returns a function
 factoryOne.someMethod();

 var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
 factoryTwo.someMethod();

Особенности Фабрики:

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

  2. Это не только производит одиночные, но и настраиваемые сервисы.

  3. .service()Метод является завод , который всегда производит один и тот же тип сервиса, который одноэлементно. Нет простого способа настроить его поведение. Этот .service()метод обычно используется в качестве ярлыка для чего-то, что не требует какой-либо настройки.



0

Вы можете понять разницу с этой аналогией - рассмотрите разницу между нормальной функцией, которая будет возвращать некоторое значение, и функцией конструктора, которая будет создана с использованием нового ключевого слова. Таким образом, создание фабрики аналогично созданию нормальной функции, которая будет возвращать некоторое значение (примитив или объект), тогда как создание службы похоже на создание функции конструктора (класс OO), для которой мы можем создать экземпляр, используя ключевое слово new. Единственное, что следует отметить, это то, что когда мы используем метод Service для создания сервисов, он автоматически создает его экземпляр, используя механизм внедрения зависимостей, поддерживаемый AngularJS.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.