301 votes

AngularJS : Quand utiliser un service plutôt qu'une fabrique

Je vous prie d'être indulgent avec moi. Je sais qu'il y a d'autres réponses telles que : AngularJS : service, fournisseur et usine

Cependant, je n'arrive toujours pas à comprendre quand on utilise le service plutôt que l'usine.

D'après ce que j'ai pu constater, la notion de "factory" est généralement utilisée pour créer des fonctions "communes" qui peuvent être appelées par plusieurs contrôleurs : Création de fonctions de contrôleur communes

La documentation d'Angular semble préférer l'usine au service. Ils font même référence à "service" lorsqu'ils utilisent factory, ce qui est encore plus déroutant ! http://docs.angularjs.org/guide/dev_guide.services.creating_services

Alors, quand utiliser le service ?

Y a-t-il quelque chose qui n'est possible ou qui est beaucoup plus facile à faire qu'avec le service ?

Y a-t-il quelque chose de différent qui se passe en coulisses ? Des différences de performance/mémoire ?

Voici un exemple. À part la méthode de déclaration, ils semblent identiques et je n'arrive pas à comprendre pourquoi je ferais l'un plutôt que l'autre. http://jsfiddle.net/uEpkE/

Mise à jour : D'après la réponse de Thomas, il semble que service soit destiné à une logique plus simple et factory à une logique plus complexe avec des méthodes privées. J'ai donc mis à jour le code ci-dessous et il semble que les deux soient capables de prendre en charge les fonctions privées ?

myApp.factory('fooFactory', function() {
    var fooVar;
    var addHi = function(foo){ fooVar = 'Hi '+foo; }

    return {
        setFoobar: function(foo){
            addHi(foo);
        },
        getFoobar:function(){
            return fooVar;
        }
    };
});
myApp.service('fooService', function() {
    var fooVar;
    var addHi = function(foo){ fooVar = 'Hi '+foo;}

    this.setFoobar = function(foo){
        addHi(foo);
    }
    this.getFoobar = function(){
        return fooVar;
    }
});

function MyCtrl($scope, fooService, fooFactory) {
    fooFactory.setFoobar("fooFactory");
    fooService.setFoobar("fooService");
    //foobars = "Hi fooFactory, Hi fooService"
    $scope.foobars = [
        fooFactory.getFoobar(),
        fooService.getFoobar()
    ];
}

0 votes

Bien sûr, le service supporte le private mais si vous lisez correctement mon post, c'est purement du style de code : nous pouvons aussi profiter d'une nouvelle portée lexicale pour simuler des variables "privées". C'est "SIMULATE".

0 votes

Je trouve cette discussion très utile stackoverflow.com/questions/15666048/

2 votes

284voto

Thomas Pons Points 3071

Explication

Vous avez des choses différentes ici :

D'abord :

  • Si vous utilisez un service, vous obtiendrez l'instance d'une fonction (" this " mot-clé).
  • Si vous utilisez une usine, vous obtiendrez la valeur qui est renvoyée en invoquant la référence de la fonction (l'instruction de retour en usine).

réf : angular.service vs angular.factory

Deuxièmement :

Gardez à l'esprit que tous les fournisseurs dans AngularJS (valeur, constante, services, usines) sont des singletons !

Troisièmement :

Utiliser l'un ou l'autre (service ou usine) est une question de style de code. Mais, le moyen commun dans AngularJS est d'utiliser usine .

Pourquoi ?

Parce que " La méthode factory est le moyen le plus courant d'introduire des objets dans le système d'injection de dépendances d'AngularJS. Elle est très flexible et peut contenir une logique de création sophistiquée. Comme les fabriques sont 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 cacher les détails de mise en œuvre d'un service donné."

( réf. : http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821 ).


Utilisation

Service : Pourrait être utile pour partager des fonctions utilitaires qui sont utiles à invoquer en ajoutant simplement () à la référence de la fonction injectée. Peut également être exécuté avec injectedArg.call(this) ou similaire.

Usine : Cela pourrait être utile pour retourner une fonction "classe" qui peut ensuite être utilisée pour créer des instances.

Donc, utiliser une usine lorsque vous avez une logique complexe à votre service et vous ne voulez pas exposer cette complexité .

Dans d'autres cas si vous voulez retourner une instance d'un service, utilisez simplement service .

Mais vous verrez avec le temps que vous utiliserez l'usine dans 80% des cas je pense.

Pour plus de détails : http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/


UPDATE :

Excellent article ici : http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html

"Si vous voulez que votre fonction pour être appelé comme une fonction normale utiliser usine . Si vous voulez que votre fonction soit instanciée avec l'opérateur new utilisez service. Si vous ne connaissez pas la différence, utilisez factory."


UPDATE :

L'équipe d'AngularJS fait son travail et donne une explication : http://docs.angularjs.org/guide/providers

Et de cette page :

"Factory" et "Service" sont les recettes les plus couramment utilisées. La seule différence entre elles est que la recette Service fonctionne mieux pour les objets de type personnalisé, tandis que Factory peut produire des primitives et des fonctions JavaScript."

7 votes

Re First : J'ai lu cela partout mais je ne comprends pas les implications pratiques de cela. Je suppose que d'après votre réponse, il n'y a pas de différence pratique "pour la plupart" ? Merci quand même pour la référence du livre !

0 votes

C'est simple, si votre service est vraiment complexe et que vous avez besoin de méthodes et d'objets privés, utilisez une fabrique.

1 votes

J'ai remarqué que vous avez ajouté "Si vous voulez renvoyer une instance d'un service, utilisez simplement service". Ma question suivante est la suivante : QUAND voulez-vous renvoyer une instance d'un service ? J'essaie de trouver un cas d'utilisation spécifique.

113voto

Jonathan. Points 15440

allernhwkim initialement publié une réponse sur cette question en établissant un lien avec son blog mais un modérateur l'a supprimé. C'est le seul article que j'ai trouvé qui ne se contente pas de vous dire comment faire la même chose avec un service, un fournisseur et une usine, mais qui vous dit aussi ce que vous pouvez faire avec un fournisseur que vous ne pouvez pas faire avec une usine, et avec une usine que vous ne pouvez pas faire avec un service.

Directement de son blog :

app.service('CarService', function() {
   this.dealer="Bad";
    this.numCylinder = 4;
});

app.factory('CarFactory', function() {
    return function(numCylinder) {
      this.dealer="Bad";
        this.numCylinder = numCylinder
    };
});

app.provider('CarProvider', function() {
    this.dealerName = 'Bad';
    this.$get = function() {
        return function(numCylinder) {
            this.numCylinder = numCylinder;
            this.dealer = this.dealerName;
        }
    };
    this.setDealerName = function(str) {
      this.dealerName = str;
    }      
});

Cela montre comment le CarService produira toujours une voiture avec 4 cylindres, vous ne pouvez pas le changer pour des voitures individuelles. Alors que CarFactory renvoie une fonction pour que vous puissiez faire new CarFactory dans votre contrôleur, en passant dans un nombre de cylindres spécifiques à cette voiture. Vous ne pouvez pas faire new CarService parce que CarService est un objet et non une fonction.

La raison pour laquelle les usines ne fonctionnent pas comme ça :

app.factory('CarFactory', function(numCylinder) {
      this.dealer="Bad";
      this.numCylinder = numCylinder
});

Et retourner automatiquement une fonction à instancier, c'est parce qu'alors vous ne pouvez pas faire cela (ajouter des choses au prototype/etc) :

app.factory('CarFactory', function() {
    function Car(numCylinder) {
        this.dealer="Bad";
        this.numCylinder = numCylinder
    };
    Car.prototype.breakCylinder = function() {
        this.numCylinder -= 1;
    };
    return Car;
});

Voyez comment il s'agit littéralement d'une usine produisant une voiture.

La conclusion de son blog est assez bonne :

En conclusion,

---------------------------------------------------  
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------  
| Factory | Yes      | Yes          | No          |
---------------------------------------------------  
| Service | Yes      | No           | No          |
---------------------------------------------------  
| Provider| Yes      | Yes          | Yes         |       
---------------------------------------------------  
  1. Utilisez Service lorsque vous avez besoin d'un objet simple tel qu'un Hash, par exemple exemple {foo;1, bar:2} C'est facile à coder, mais vous ne pouvez pas l'instancier. l'instancier.

  2. Utilisez Factory lorsque vous avez besoin d'instancier un objet, par exemple new Client(), nouveau Commentaire(), etc.

  3. Utilisez Provider lorsque vous avez besoin de le configurer, c'est-à-dire test url, QA url, url de production.

Si vous vous apercevez que vous ne faites que renvoyer un objet en factory, vous devriez probablement utiliser service.

Ne faites pas ça :

app.factory('CarFactory', function() {
    return {
        numCylinder: 4
    };
});

Utilisez plutôt le service :

app.service('CarService', function() {
    this.numCylinder = 4;
});

22voto

luisperezphd Points 3220

Le concept de tous ces prestataires est beaucoup plus simple qu'il n'y paraît au premier abord. Si vous disséquez un fournisseur et que vous en retirez les différentes parties, cela devient très clair.

Pour faire simple, chacun de ces fournisseurs est une version spécialisée de l'autre, dans cet ordre : provider > factory > value / constant / service .

Tant que le fournisseur fait ce que vous voulez, vous pouvez l'utiliser plus bas dans la chaîne, ce qui vous permettra d'écrire moins de code. S'il n'accomplit pas ce que vous voulez, vous pouvez remonter la chaîne et vous devrez écrire plus de code.

Cette image illustre ce que je veux dire, dans cette image vous verrez le code d'un fournisseur, avec les parties surlignées vous montrant quelles parties du fournisseur pourraient être utilisées pour créer une usine, une valeur, etc à la place.

AngularJS providers, factories, services, etc are all the same thing
(source : <a href="http://www.simplygoodcode.com/wp-content/uploads/2015/11/angularjs-provider-service-factory-highlight.png" rel="nofollow noreferrer">simplygoodcode.com </a>)

Pour plus de détails et d'exemples tirés de l'article du blog d'où provient l'image, rendez-vous sur le site : http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/

8voto

Steve Lang Points 299

La fabrique et le service produisent des objets singletons qui peuvent être configurés par les fournisseurs et injectés dans les contrôleurs et les blocs d'exécution. Du point de vue de l'injecté, il n'y a absolument aucune différence entre l'objet provenant d'une usine ou d'un service.

Alors, quand utiliser une usine, et quand utiliser un service ? Cela se résume à vos préférences en matière de codage, et à rien d'autre. Si vous aimez le modèle JS modulaire, optez pour la fabrique. Si vous aimez le style de la fonction de construction ("classe"), optez pour le service. Notez que les deux styles prennent en charge les membres privés.

L'avantage du service pourrait être qu'il est plus intuitif du point de vue de la POO : créer une "classe", et, en conjonction avec un fournisseur, réutiliser le même code à travers les modules, et varier le comportement des objets instanciés simplement en fournissant différents paramètres au constructeur dans un bloc de configuration.

0 votes

Pourriez-vous fournir un exemple de ce que vous entendez par fournir différents paramètres au constructeur dans un bloc de configuration ? Comment fournir des paramètres s'il s'agit simplement d'un service ou d'une usine ? Que voulez-vous dire par "en conjonction avec un fournisseur" ? Le fait de pouvoir le configurer me fait penser que beaucoup de mes objets devraient être des providers plutôt que des factories ou des services.

2voto

Andrew Krook Points 29

Il n'y a rien qu'une usine ne puisse faire ou fasse mieux qu'un service. Et vice versa. Factory semble simplement être plus populaire. La raison en est sa facilité à gérer les membres privés/publics. Un service serait plus maladroit à cet égard. En codant un Service, vous avez tendance à rendre les membres de votre objet publics via le mot-clé "this" et vous pouvez soudainement découvrir que ces membres publics ne sont pas visibles par les méthodes privées (c'est-à-dire les fonctions internes).

var Service = function(){

  //public
  this.age = 13;

  //private
  function getAge(){

    return this.age; //private does not see public

  }

  console.log("age: " + getAge());

};

var s = new Service(); //prints 'age: undefined'

Angular utilise le mot clé "new" pour créer un service pour vous, donc l'instance qu'Angular transmet au contrôleur aura le même inconvénient. Bien sûr, vous pouvez surmonter le problème en utilisant this/that :

var Service = function(){

  var that = this;

  //public
  this.age = 13;

  //private
  function getAge(){

    return that.age;

  }

  console.log("age: " + getAge());

};

var s = new Service();// prints 'age: 13'  

Mais avec une grande constante de service, cette \that -rendrait le code peu lisible. De plus, les prototypes de service ne verront pas les membres privés - seuls les membres publics seront disponibles pour eux :

var Service = function(){

  var name = "George";

};

Service.prototype.getName = function(){

  return this.name; //will not see a private member

};

var s = new Service();
console.log("name: " + s.getName());//prints 'name: undefined'

En résumé, l'utilisation de Factory est plus pratique. Comme Factory n'a pas ces inconvénients. Je recommande de l'utiliser par défaut.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X