Confus au sujet du service par rapport à l'usine

618

Si je comprends bien, à l'intérieur d'une usine, je retourne un objet qui est injecté dans un contrôleur. Lorsque je suis à l'intérieur d'un service, je traite l'objet en utilisant thiset en ne retournant rien.

J'étais sous l'hypothèse qu'un service a toujours été un singleton et qu'un nouvel objet d'usine est injecté dans chaque contrôleur. Cependant, il s'avère qu'un objet d'usine est aussi un singleton?

Exemple de code pour démontrer:

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;
});

Lors d'un changement user.firstdans ACtrlil se trouve que user.firstdans BCtrlest également modifiée, par exemple , Userest un singleton?

Mon hypothèse était qu'une nouvelle instance a été injectée dans un contrôleur avec une usine?

JvdBerg
la source
4
À côté de "module.service" et "module.factory", il existe 2 autres façons de créer des services dans AngularJS. Pour plus d'informations, consultez l'article de blog: " Comment créer (singleton) des services AngularJS de 4 manières différentes "
Emil van Galen
Duplication possible de angular.service vs angular.factory
Kaushal28

Réponses:

600

Tous les services angulaires sont des singletons :

Documents (voir Services en tant que singletons ): https://docs.angularjs.org/guide/services

Enfin, il est important de réaliser que tous les services angulaires sont des singletons d'application. Cela signifie qu'il n'y a qu'une seule instance d'un service donné par injecteur.

Fondamentalement, la différence entre le service et l'usine est la suivante:

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 + "!";
    }
  }
});

Découvrez cette présentation sur $ provide: http://slides.wesalvaro.com/20121113/#/

Ces diapositives ont été utilisées dans l'un des Meetups AngularJs: http://blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html

matys84pl
la source
13
Voir également stackoverflow.com/questions/15666048/… qui traite des différences entre le service, l'usine et la fourniture.
Mark Rajcok
31
Le doc officiel indirectement [sic! pas assez clair] implique que même si vous définissez le service avec l'usine, il n'est créé qu'une seule fois. En d'autres termes, il n'est PAS recréé selon la référence (point d'injection), peu importe comment vous l'appelez. Les deux manières aboutissent à une instance singleton par injecteur.
honzajde
3
Vous dites que "le service n'est qu'une fonction constructeur qui sera appelée avec" nouveau "" mais je pense que c'est trompeur. Je ne pense pas que cela s'appelle avec de nouvelles coulisses, je pense que le développeur est responsable de l'appel new.
Tim Kindberg
5
@nfiniteloop, vérifiez le code source près de la ligne 3574. Les usines sont la méthode $ get d'un fournisseur et les services génèrent des usines en utilisant une méthode qui appelle $ injector.instantiate sur la fonction fournie, qui appelle ensuite new. ( Voir Docs )
citizenslave
14
J'avais l'impression qu'un service était aussi simple que vous l'avez utilisé en obtenant une référence. Et qu'une usine était un singleton qui renvoyait un nouvel objet à chaque fois. Autrement dit, un service vous donnerait une "voiture" et tout dans votre projet utiliserait cette voiture. Alors qu'une usine vous donnerait une nouvelle voiture à chaque fois que vous invoquiez l'usine. L'un était un singleton qui renvoyait un singleton et l'autre était un singleton qui renvoyait un objet. Quelqu'un peut-il expliquer? Appeler tout un singleton n'aide pas car il peut se référer à plusieurs choses.
user2483724
380

Pour moi, la révélation est venue quand je me rends compte qu'ils fonctionnent tous de la même manière: en exécutant quelque chose une fois , en stockant la valeur qu'ils obtiennent, puis en crachant cette même valeur stockée lorsqu'ils sont référencés via l'injection de dépendance.

Disons que nous avons:

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

La différence entre les trois est que:

  1. aLa valeur stockée provient de l'exécution fn, en d'autres termes:fn()
  2. bLa valeur stockée provient de newing fn, en d'autres termes:new fn()
  3. cLa valeur stockée provient d'abord de l'obtention d'une instance par newing fn, puis de l'exécution d'une $getméthode de l'instance

ce qui signifie qu'il y a quelque chose comme un objet cache à l'intérieur angulaire, dont la valeur de chaque injection n'est assignée qu'une seule fois, lors de leur première injection, et où:

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

C'est pourquoi nous utilisons des thisservices et définissons un this.$getfournisseur.

J'espère que cela t'aides.

Lucia
la source
54
enfin, une explication sensée. Angular est fou et tellement mauvais que ça fait mal.
osiris
8
Cela devrait être la réponse acceptée car elle répond en fait à la question de savoir POURQUOI les usines, les services et les fournisseurs renvoient des valeurs singleton. Les autres réponses expliquent la différence entre les usines, les services et les fournisseurs, mais ne touchent jamais à l'aspect singleton.
wmock
3
J'aime ça ... Quand je lis les mille lignes de phrase d'un autre blogueur .. je n'arrive qu'à comprendre l'usine. Mais j'ai lu ceci ... je comprends tout 3.
tsohtan
@osiris, je suis d'accord. Je n'aime pas ça. Cela me semble tellement flippant étroitement couplé qu'il fait grincer des dents.
Thomas
2
vous devez donc fournir une implémentation de $ get lorsque vous utilisez des fournisseurs?
Victor
95

exemple en direct

exemple "bonjour le monde"

avec 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()];
}​
EpokK
la source
57

Il existe également un moyen de renvoyer une fonction constructeur afin que vous puissiez retourner des classes pouvant être renouvelées dans des usines, comme ceci:

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 });
  };
}); 

Vous pouvez donc le faire dans un contrôleur, qui utilise MyObjectWithParam:

var obj = new MyObjectWithParam("hello"),

Voir ici l'exemple complet:
http://plnkr.co/edit/GKnhIN?p=preview

Et voici les pages du groupe Google, où il a été discuté:
https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ

JustGoscha
la source
J'ai des problèmes avec la minification en utilisant votre exemple. Savez-vous comment annoter cela?
Pål
2
Oui, il existe une notation minifiée pour Angular. Cela devrait ressembler à ceci: App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); En savoir plus ici: docs.angularjs.org/tutorial/step_05
JustGoscha
4
pourquoi voudriez-vous faire cela, si vous pouvez utiliser à la .serviceplace?
flup
j'ai eu la même pensée @flup. @justgoscha, y a-t-il un avantage ( perçu? ) à utiliser .factorypar opposition à .service?
Xandercodé
5
Je pense que parce qu'un service est un singleton . Ce que j'ai construit ici est essentiellement une classe qui est renouvelable. Donc, vous pouvez avoir quelque chose comme une usine de services automobiles, puis faire new Car('BMW')et new Car('Ford')et ils ne partagent pas les mêmes variables et tout.
JustGoscha
51

Voici les principales différences:

Prestations de service

Syntaxe: module.service( 'serviceName', function );

Résultat: Lorsque vous déclarez serviceName comme argument injectable, vous recevrez l' instance d'une fonction passée à module.service.

Utilisation: pourrait être utile pour partager des fonctions utilitaires qu'il est utile d'invoquer en ajoutant simplement () à la référence de fonction injectée. Peut également être exécuté avec injectedArg.call( this )ou similaire.

Des usines

Syntaxe: module.factory( 'factoryName', function );

Résultat: lorsque vous déclarez factoryName en tant qu'argument injectable, la valeur renvoyée vous sera fournie en invoquant la référence de fonction passée à module.factory.

Utilisation: pourrait être utile pour renvoyer une fonction «classe» qui peut ensuite être renouvelée pour créer des instances.

Vérifiez également la documentation AngularJS et une question similaire sur stackoverflow confus à propos du service par rapport à l'usine .

Voici un exemple d'utilisation de services et d'usine . En savoir plus sur le service AngularJS par rapport à l'usine .

Manish Chhabra
la source
6
Cela me semble logique. L'usine he renvoie le plan de création de nouveaux objets.
27

Pour ajouter à la première réponse, je pense que .service () est destiné aux personnes qui ont écrit leur code dans un style plus orienté objet (C # / Java) (en utilisant ce mot-clé et en instanciant l'objet via la fonction prototype / constructeur).

Factory est destiné aux développeurs qui écrivent du code plus naturel pour le style de codage javascript / fonctionnel.

Jetez un œil au code source de la méthode .service et .factory dans angular.js - en interne, ils appellent tous la méthode du fournisseur:

  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);
    }]);
  }
Anand
la source
25

Très simplement:

.service - la fonction enregistrée sera invoquée en tant que constructeur (aka 'newed')

.factory - la fonction enregistrée sera invoquée comme une fonction simple

Les deux sont invoqués une fois, ce qui crée un objet singleton qui est injecté dans d'autres composants de votre application.

bingles
la source
6
Oui. ne rendons pas les choses plus compliquées qu'elles ne le sont vraiment
flup
20

Tous les fournisseurs fonctionnent de la même manière. Les différentes méthodes service, factory, providerjuste vous permettent de faire la même chose en moins de code.

PS Il y a aussi valueet constant.

Chaque cas spécial dans la chaîne commençant par provideret se terminant par valuea une limitation supplémentaire. Donc, pour décider entre eux, vous devez vous demander lequel vous permet d'accomplir ce que vous voulez avec moins de code.

Voici une photo qui vous montre ce que je veux dire:

entrez la description de l'image ici

Vous pouvez un guide de ventilation et de référence sur le blog où j'ai obtenu cette image:

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

Luis Perez
la source
On dit que les services sont singleton, mais comment se fait-il que ce soit un singleton, si une nouvelle instance est créée à chaque fois que je l'injecte?
Ankur Marwaha
1
@AnkurMarwaha Une nouvelle instance n'est pas créée à chaque fois, elle n'est créée qu'une seule fois et mise en cache par AngularJS. Cela est vrai que vous utilisiez un fournisseur, une usine, un service, etc. Vous pouvez le confirmer en utilisantconsole.log() et en injectant dans plusieurs contrôleurs.
Luis Perez
Luis, Votre commentaire est en conflit avec la réponse acceptée car elle dit - Enfin, il est important de réaliser que tous les services angulaires sont des singletons d'application. Cela signifie qu'il n'y a qu'une seule instance d'un service donné par injecteur.
Ankur Marwaha
@AnkurMarwaha peut-être que je me méprends sur quelque chose. Vous avez cité "il est important de réaliser que tous les services angulaires sont des singletons d'application" - le fait qu'ils soient singletons signifie qu'ils ne sont créés qu'une seule fois. C'est ce que j'ai dit "Une nouvelle instance n'est pas créée à chaque fois, elle n'est créée qu'une seule fois et mise en cache ...". Pouvez-vous indiquer plus en détail où vous voyez le conflit?
Luis Perez
1
Ah, je vois la confusion. L '"injecteur" est un objet en angulaire. Il est chargé de faire l'injection. Exemple, lorsque le contrôleur est exécuté pour la première fois, l '"injecteur" examine les paramètres et injecte chacun. Il n'y a qu'un seul "injecteur" pour l'ensemble de votre application. Une fois que l'injecteur crée une usine ou un service particulier, il conserve une instance et la réutilise - d'où le singleton. Il n'y a donc qu'un seul injecteur par application et une seule instance d'un service donné par injecteur. La plupart des applications angulaires n'ont qu'une seule application, donc un injecteur, donc une instance de n'importe quel service, contrôleur, etc.
Luis Perez
13

Voici quelques exemples supplémentaires de services vs usines qui peuvent être utiles pour voir la différence entre eux. Fondamentalement, un service est appelé "nouveau ...", il est déjà instancié. Une fabrique n'est pas instanciée automatiquement.

Exemples de base

Renvoie un objet de classe qui a une seule méthode

Voici un service qui a une seule méthode:

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

Voici une fabrique qui renvoie un objet avec une méthode:

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

Renvoyer une valeur

Une usine qui renvoie une liste de nombres:

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

console.log(NumberListFactory);

Un service qui renvoie une liste de numéros:

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

console.log(NumberLister.numbers);

La sortie dans les deux cas est la même, la liste des nombres.

Exemples avancés

Variables de "classe" utilisant des usines

Dans cet exemple, nous définissons un CounterFactory, il incrémente ou décrémente un compteur et vous pouvez obtenir le nombre actuel ou obtenir combien d'objets CounterFactory ont été créés:

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;
    };
  }

})

Nous utilisons le CounterFactorypour créer plusieurs compteurs. Nous pouvons accéder à la variable de classe pour voir combien de compteurs ont été créés:

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());

La sortie de ce code est:

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

la source
c'est un exemple utile, number_of_counter_factories est comme un méta-attribut de la classe CounterFactory, non?, je comprends que cet exemple est reproductible sur un service (dites-moi si je me trompe), quelle serait la différence sémantique dans ce cas?
geoom
Exemple utile! Donc, cela signifie essentiellement que dans une usine, vous pouvez avoir cette couche d'abstraction supplémentaire qui ne serait pas incluse dans un service. Quoi qu'il en soit, une nouvelle instance sera retournée chaque fois que «new» est utilisé. Toutes les variables qui ne sont pas déclarées à l'intérieur du bloc de retour seront singleton. Ai-je bien compris?
Swanidhi
@Swanidhi fondamentalement oui, vous pouvez déclarer des variables qui sont des singletons en usine. C'est pourquoi je les ai appelés variables de "classe".
13

«Factory» et «Service» sont des façons différentes de faire DI (injection de dépendance) en angulaire.

Ainsi, lorsque nous définissons DI à l'aide de «service», comme indiqué dans le code ci-dessous. Cela crée une nouvelle instance GLOBALE de l'objet «Logger» et l'injecte dans la fonction.

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

Lorsque vous définissez DI à l'aide d'une «usine», il ne crée pas d'instance. Il passe simplement la méthode et plus tard, le consommateur doit en interne appeler la fabrique pour les instances d'objet.

app.factory("Customerfactory", CreateCustomer);

Ci-dessous est une image simple qui montre visuellement comment le processus DI pour "Service" est différent de "Factory".

entrez la description de l'image ici

L'usine doit être utilisée lorsque nous voulons créer différents types d'objets en fonction des scénarios. Par exemple, selon le scénario, nous voulons créer un simple objet "Client", ou "Client" avec l'objet "Adresse" ou "Client" avec l'objet "Téléphone". Voici une explication détaillée de ce paragraphe

Le service doit être utilisé lorsque nous avons des fonctions utilitaires ou partagées à injecter comme l'utilitaire, l'enregistreur, le gestionnaire d'erreurs, etc.

Shivprasad Koirala
la source
Chaque réponse que j'ai vue sur cette question et d'autres similaires spécifie la différence de mécanique et de syntaxe. Cette réponse donne une vraie raison pour laquelle vous choisiriez l'un plutôt que l'autre. C'est une question de sémantique et de regarder le nom, le service ou l'usine, communique leur objectif et comment ils sont utilisés.
Joe Mayo
8

Style de service : ( probablement le plus simple ) renvoie la fonction réelle: Utile pour partager des fonctions utilitaires qu'il est utile d'invoquer en ajoutant simplement () à la référence de fonction injectée.

Un service dans AngularJS est un objet JavaScript singleton qui contient un ensemble de fonctions

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();

});

Style d' usine : ( plus impliqué mais plus sophistiqué ) renvoie la valeur de retour de la fonction: instancier un objet comme new Object () en java.

Factory est une fonction qui crée des valeurs. Lorsqu'un service, un contrôleur, etc. a besoin d'une valeur injectée à partir d'une usine, l'usine crée la valeur à la demande. Une fois créée, la valeur est réutilisée pour tous les services, contrôleurs, etc. qui en ont besoin.

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);

});

Style du fournisseur : (version complète configurable ) renvoie la sortie de la fonction $ get de la fonction: Configurable.

Les fournisseurs dans AngularJS est la forme d'usine la plus flexible que vous puissiez créer. Vous enregistrez un fournisseur avec un module comme vous le faites avec un service ou une usine, sauf que vous utilisez la fonction provider () à la place.

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

Premraj
la source
2

La différence de base est que le fournisseur permet de définir des valeurs de fonction primitives (non-objets), de tableau ou de rappel dans la variable déclarée en usine, et donc si vous retournez un objet, il doit être explicitement déclaré et renvoyé.

D'un autre côté, un service ne peut être utilisé que pour définir la variable déclarée de service sur un objet, ainsi nous pouvons éviter la création explicite et le retour des objets, tandis que d'un autre côté il permet l'utilisation du mot - clé this .

Ou en bref, "le fournisseur est une forme plus générique alors que le service est limité aux objets uniquement".

yoel halb
la source
2

C'est ainsi que j'ai compris la différence entre eux en termes de modèles de conception:

Service : retourne un type, qui sera nouveau pour créer un objet de ce type. Si l'analogie Java est utilisée, Service renvoie une définition de classe Java .

Factory : renvoie un objet concret qui peut être immédiatement utilisé. Dans Java Analogy, une usine renvoie un objet Java .

La partie qui déroute souvent les gens (y compris moi-même) est que lorsque vous injectez un service ou une usine dans votre code, ils peuvent être utilisés de la même manière, ce que vous obtenez dans votre code dans les deux cas est un objet concret que vous pouvez immédiatement invoquer. Ce qui signifie en cas de Service, angulaire appelle "nouveau" sur la déclaration de service en votre nom. Je pense que c'est un concept compliqué.

Hisham
la source
1

Ce serait la meilleure et courte réponse pour comprendre Service Vs Factory Vs Provider

Source : https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/HuZsOsMvKv4J

Voici ce que ben dit avec une démo http://jsbin.com/ohamub/1/edit?html,output

"Il y a des commentaires dans le code illustrant les principales différences, mais je vais les développer un peu ici. En guise de remarque, je me renseigne, donc si je dis quelque chose qui ne va pas, faites-le moi savoir.

Prestations de service

Syntaxe : module.service ('serviceName', fonction);

Résultat : lorsque vous déclarez serviceName comme argument injectable, la référence de fonction réelle transmise à module.service vous sera fournie.

Utilisation : pourrait être utile pour partager des fonctions utilitaires qu'il est utile d'invoquer en ajoutant simplement () à la référence de fonction injectée. Peut également être exécuté avec injectedArg.call (this) ou similaire.

Des usines

Syntaxe : module.factory ('factoryName', fonction);

Résultat : lorsque vous déclarez factoryName en tant qu'argument injectable, vous recevrez la valeur renvoyée en appelant la référence de fonction transmise à module.factory.

Utilisation : pourrait être utile pour renvoyer une fonction «classe» qui peut ensuite être renouvelée pour créer des instances.

Fournisseurs

Syntaxe : module.provider ('providerName', fonction);

Résultat : lors de la déclaration de providerName comme argument injectable, la valeur renvoyée vous sera fournie en appelant la méthode $ get de la référence de fonction transmise à module.provider.

Utilisation : pourrait être utile pour renvoyer une fonction «classe» qui peut ensuite être renouvelée pour créer des instances mais qui nécessite une sorte de configuration avant d'être injectée. Peut-être utile pour les classes réutilisables sur plusieurs projets? Toujours un peu flou sur celui-ci. "Ben

Syed Ekram Uddin
la source
1

J'ai eu cette confusion pendant un certain temps et je fais de mon mieux pour fournir une explication simple ici. J'espère que cela vous aidera!

angular .factoryet les angular .servicedeux sont utilisés pour initialiser un service et fonctionner de la même manière.

La seule différence est la façon dont vous souhaitez initialiser votre service.

Les deux sont Singletons


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


Usine

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

Si vous souhaitez initialiser votre service à partir d' une fonction que vous avez avec une valeur de retour , vous devez utiliser cette factoryméthode.

par exemple

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

app.factory('myService', myService);

Lors de l'injection de ce service (par exemple à votre contrôleur):

  • Angular appellera votre fonction donnée (as myService()) pour retourner l'objet
  • Singleton - appelé une seule fois, stocké et passe le même objet.


Un service

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

Si vous souhaitez initialiser votre service à partir d' une fonction constructeur (à l'aide d'un thismot-clé), vous devez utiliser cette serviceméthode.

par exemple

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

app.service('myService', myService);

Lors de l'injection de ce service (par exemple à votre contrôleur):

  • Angulaire veut newvotre fonction donnée (as new myService()) pour retourner l'objet
  • Singleton - appelé une seule fois, stocké et passe le même objet.


REMARQUE: Si vous utilisez factoryavec <constructor function>ou serviceavec <function with a return value>, cela ne fonctionnera pas.


Exemples - DEMO

Safeer Hussain
la source
1

C'est ce qui m'a aidé à comprendre la différence, grâce à un article de blog de Pascal Precht.

Un service est une méthode sur un module qui prend un nom et une fonction qui définit le service. Vous pouvez injecter et utiliser ce service particulier dans d'autres composants, comme les contrôleurs, les directives et les filtres. Une usine est une méthode sur un module et elle prend également un nom et une fonction, qui définit l'usine. Nous pouvons également injecter et utiliser de la même manière que nous l'avons fait avec le service.

Les objets créés avec new utilisent la valeur de la propriété prototype de leur fonction constructeur comme prototype, j'ai donc trouvé le code angulaire qui appelle Object.create (), qui, selon moi, est la fonction constructeur de service lorsqu'elle est instanciée. Cependant, une fonction d'usine n'est en réalité qu'une fonction qui est appelée, c'est pourquoi nous devons renvoyer un objet littéral pour l'usine.

Voici le code angulaire 1.5 que j'ai trouvé en usine:

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

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

Extrait de code source angulaire pour la fonction factory ():

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

Il prend le nom et la fonction d'usine qui sont passés et retourne un fournisseur avec le même nom, qui a une méthode $ get qui est notre fonction d'usine. Chaque fois que vous demandez à l'injecteur une dépendance spécifique, il demande essentiellement au fournisseur correspondant une instance de ce service, en appelant la méthode $ get (). C'est pourquoi $ get () est requis lors de la création de fournisseurs.

Voici le code angulaire 1.5 pour le service.

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

Il s'avère que lorsque nous appelons service (), il appelle en fait factory ()! Cependant, il ne transmet pas simplement notre fonction de constructeur de services à l'usine telle quelle. Il transmet également une fonction qui demande à l'injecteur d'instancier un objet par le constructeur donné.

En d'autres termes, si nous injectons MyService quelque part, ce qui se passe dans le code est:

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

Pour le reformuler, un service appelle une fabrique, qui est une méthode $ get () sur le fournisseur correspondant. De plus, $ injector.instantiate () est la méthode qui appelle finalement Object.create () avec la fonction constructeur. C'est pourquoi nous utilisons "ceci" dans les services.

Pour ES5, peu importe ce que nous utilisons: service () ou usine (), c'est toujours une usine appelée qui crée un fournisseur pour notre service.

Vous pouvez également faire exactement la même chose avec les services. Un service est une fonction constructeur, cependant, qui ne nous empêche pas de renvoyer des littéraux d'objet. Nous pouvons donc prendre notre code de service et l'écrire de manière à ce qu'il fasse exactement la même chose que notre usine ou en d'autres termes, vous pouvez écrire un service en tant qu'usine pour retourner un objet.

Pourquoi la plupart des gens recommandent-ils d'utiliser les usines plutôt que les services? C'est la meilleure réponse que j'ai vue qui vient du livre de Pawel Kozlowski: Mastering Web Application Development with AngularJS.

La méthode d'usine est le moyen le plus courant d'intégrer des objets dans le système d'injection de dépendance AngularJS. Il est très flexible et peut contenir une logique de création sophistiquée. Les usines étant des fonctions régulières, nous pouvons également profiter d'une nouvelle portée lexicale pour simuler des variables "privées". Ceci est très utile car nous pouvons masquer les détails d'implémentation d'un service donné. "

James Drinkard
la source
1
  • Avec l' usine, vous créez un objet à l' intérieur de l' usine et vous le retournez.
  • Avec le service, vous avez juste une fonction standard qui utilise le thismot - clé pour définir la fonction.
  • Avec le fournisseur, il y a un que $getvous définissez et il peut être utilisé pour obtenir l'objet qui renvoie les données.
Oskar
la source
1

Il existe trois façons de gérer la logique métier dans AngularJS: ( Inspiré du cours Coursera AngularJS de Yaakov ) qui sont:

  1. Un service
  2. Usine
  3. Fournisseur

Ici, nous allons seulement parler de Service vs Factory

SERVICE :

Syntaxe:

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>

Les principales caractéristiques du service:

  1. Paresseusement instancié : Si le service n'est pas injecté, il ne sera jamais instancié. Donc, pour l'utiliser, vous devrez l'injecter dans un module.

  2. Singleton : s'il est injecté dans plusieurs modules, tous n'auront accès qu'à une seule instance particulière. C'est pourquoi, il est très pratique de partager des données entre différents contrôleurs.

USINE

Parlons maintenant de l'usine dans AngularJS

Voyons d'abord la syntaxe :

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;
}

Maintenant, en utilisant les deux ci-dessus dans le contrôleur:

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

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

Caractéristiques de l'usine:

  1. Ces types de services suivent le modèle de conception d'usine . L'usine peut être considérée comme un lieu central qui crée de nouveaux objets ou méthodes.

  2. Cela ne produit pas seulement des singleton, mais aussi des services personnalisables.

  3. La .service()méthode est une usine qui produit toujours le même type de service, qui est un singleton. Il n'y a aucun moyen facile de configurer son comportement. Cette .service()méthode est généralement utilisée comme raccourci pour quelque chose qui ne nécessite aucune configuration.

Pritam Banerjee
la source
0

Vous pouvez comprendre la différence avec cette analogie - Considérez la différence entre une fonction normale qui renverra une valeur et une fonction constructeur qui sera instanciée à l'aide d'un nouveau mot-clé. un objet) alors que créer un service est comme créer une fonction constructeur (classe OO) dont nous pouvons créer une instance en utilisant un nouveau mot clé. La seule chose à noter est que lorsque nous utilisons la méthode Service pour créer des services, elle en créera automatiquement une instance à l'aide du mécanisme d'injection de dépendances pris en charge par AngularJS.

Sourabh Ranka
la source