AngularJS: quand utiliser le service au lieu de l'usine

296

S'il vous plaît, restez avec moi ici. Je sais qu'il existe d'autres réponses telles que: AngularJS: Service vs fournisseur vs usine

Cependant, je ne sais toujours pas quand vous utiliserez le service par rapport à l'usine.

D'après ce que je peux dire, l'usine est couramment 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

Les documents angulaires semblent préférer l'usine au service. Ils parlent même de "service" lorsqu'ils utilisent l'usine, ce qui est encore plus déroutant! http://docs.angularjs.org/guide/dev_guide.services.creating_services

Alors, quand utiliserait-on le service?

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

Y a-t-il quelque chose de différent qui se passe dans les coulisses? Différences performances / mémoire?

Voici un exemple. À part la méthode de déclaration, ils semblent identiques et je ne peux pas comprendre pourquoi je ferais l'un contre l'autre. http://jsfiddle.net/uEpkE/

Mise à jour: D'après la réponse de Thomas, cela semble impliquer que le service est pour une logique plus simple et une usine pour une logique plus complexe avec des méthodes privées, j'ai donc mis à jour le code du violon ci-dessous et il semble que les deux sont capables de prendre en charge des 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()
    ];
}
user1941747
la source
bien sûr, le service prend en charge private mais si vous lisez correctement mon article, c'est purement du code: nous pouvons également profiter d'une nouvelle portée lexicale pour simuler des variables "privées". C'est "SIMULÉ"
Thomas Pons
Je trouve cette discussion très utile stackoverflow.com/questions/15666048/…
Anand Gupta
2
Il y a aussi de bonnes réponses ici .
Mistalis

Réponses:

280

Explication

Vous avez des choses différentes ici:

Première:

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

réf: angular.service vs angular.factory

Seconde:

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

Troisième:

L'utilisation de l'un ou de l'autre (service ou usine) concerne le style de code. Mais, la manière courante dans AngularJS est d'utiliser Factory .

Pourquoi ?

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

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


Usage

Service: 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.

Factory: pourrait être utile pour renvoyer une fonction de «classe» qui peut ensuite être nouvelle pour créer des instances.

Donc, utilisez une fabrique lorsque vous avez une logique complexe dans votre service et que vous ne voulez pas exposer cette complexité .

Dans d'autres cas, si vous souhaitez renvoyer 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/


METTRE À JOUR :

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

"Si vous voulez que votre fonction soit appelée comme une fonction normale , utilisez l' usine . Si vous voulez que votre fonction soit instanciée avec le nouvel opérateur, utilisez le service. Si vous ne connaissez pas la différence, utilisez l'usine."


METTRE À JOUR :

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

Et à partir de cette page:

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

Thomas Pons
la source
7
Re First: Je l'ai lu 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 pour la référence du livre!
user1941747
C'est simple si votre service est vraiment complexe et que vous avez besoin de méthodes et d'objets privés utilisez une usine
Thomas Pons
1
J'ai remarqué que vous avez ajouté "Si vous souhaitez renvoyer une instance d'un service, utilisez simplement service". Ma question de suivi serait QUAND voudriez-vous retourner une instance d'un service? J'essaie de trouver un cas d'utilisation spécifique ici.
user1941747
12
"Les usines étant des fonctions régulières, nous pouvons également profiter d'une nouvelle portée lexicale pour simuler des variables" privées "." - ce n'est pas spécifique aux usines, vous pouvez faire de même avec les services ..
pootzko
Il semble que l'équipe Google préfère le service à l'usine, ce qui rend les choses encore plus confuses! google-styleguide.googlecode.com/svn/trunk/…
xzhang
111

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

Directement depuis 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 à 4 cylindres, vous ne pouvez pas la changer pour des voitures individuelles. Alors que CarFactory renvoie une fonction que vous pouvez faire new CarFactorydans votre contrôleur, en passant un certain nombre de cylindres spécifiques à cette voiture. Vous ne pouvez pas le faire new CarServicecar CarService est un objet et non une fonction.

La raison pour laquelle les usines ne fonctionnent pas comme ceci:

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

Et retourner automatiquement une fonction pour que vous puissiez l'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 c'est littéralement une usine qui produit une voiture.

La conclusion de son blog est plutôt 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 simple objet tel qu'un hachage, par exemple {foo; 1, bar: 2} Il est facile de coder, mais vous ne pouvez pas l'instancier.

  2. Utilisez Factory lorsque vous devez instancier un objet, c'est-à-dire un nouveau client (), un nouveau commentaire (), etc.

  3. Utilisez Provider lorsque vous devez le configurer. c.-à-d. URL de test, URL QA, URL de production.

Si vous trouvez que vous venez de renvoyer un objet en usine, vous devriez probablement utiliser le service.

Ne faites pas ça:

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

Utilisez plutôt le service:

app.service('CarService', function() {
    this.numCylinder = 4;
});
Jonathan.
la source
11
Ça m'aide beaucoup. +1 pour le tableau de comparaison
Vu Anh
5
si vous définissez la fonction de service avec un paramètre numCylinder, elle aura la même flexibilité que la méthode d'usine
Ovi
allez lire le blog de l'article et perdez votre temps à essayer de comprendre angulaire, si vous connaissez javascript après avoir lu cet article, vous comprendrez totalement la différence entre cela.
ncubica
4
Très surpris ! Vous parlez d'un blog ici et les deux disent une chose complètement opposée. Vous dites: Factory - Instantiable - Oui Blog say: Factory - Instantiable - No
Devesh M
1
Je suis d'accord avec @Devesh. Je pense que vous avez mélangé les instanciations. Du billet de blog: "Seulement avec l'usine, vous ne pouvez pas y parvenir car l'usine ne peut pas être instanciée".
Matt
20

Le concept pour tous ces fournisseurs est beaucoup plus simple qu'il n'y paraît au départ. Si vous disséquez un fournisseur et retirez les différentes parties, cela devient très clair.

Pour le dire simplement 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 pouvez, vous pouvez utiliser le fournisseur plus bas dans la chaîne, ce qui entraînerait l'écriture de moins de code. S'il n'accomplit pas ce que vous voulez, vous pouvez remonter la chaîne et vous n'aurez qu'à é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 en surbrillance vous montrant quelles parties du fournisseur pourraient être utilisées pour créer une usine, une valeur, etc. à la place.

Fournisseurs AngularJS, usines, services, etc. sont tous la même chose
(source: simplygoodcode.com )

Pour plus de détails et d'exemples à partir du blog où j'ai obtenu l'image, allez sur: http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/

Luis Perez
la source
8

L'usine et le service entraînent des objets singleton 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 que l'objet provienne d'une usine ou d'un service.

Alors, quand utiliser une usine et quand utiliser un service? Cela se résume à votre préférence de codage, et rien d'autre. Si vous aimez le modèle JS modulaire, optez pour l'usine. Si vous aimez le style de fonction constructeur ("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 POO: créer une "classe", et, en collaboration avec un fournisseur, réutiliser le même code entre les modules, et varier le comportement des objets instanciés simplement en fournissant différents paramètres au constructeur dans un bloc de configuration.

Steve Lang
la source
Pourriez-vous fournir un exemple de ce que vous entendez par fournir différents paramètres au constructeur dans un bloc de configuration? Comment fournissez-vous des paramètres si c'est juste un service ou une usine. Qu'entendez-vous par «en collaboration avec un fournisseur»? Le fait de pouvoir le configurer me fait penser que beaucoup de mes objets devraient être des fournisseurs vs des usines ou des services.
timbrown
2

Il n'y a rien qu'une Usine ne puisse faire ou fait mieux par rapport à un Service. Et vice-versa. L'usine semble juste être plus populaire. La raison en est sa commodité dans la gestion des membres privés / publics. Le service serait plus maladroit à cet égard. Lorsque vous codez un service, vous avez tendance à rendre publics les membres de votre objet via «ce» mot-clé et vous découvrirez soudainement 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 Angular passe au contrôleur aura le même inconvénient. Bien sûr, vous pouvez surmonter le problème en utilisant ceci / cela:

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, cela \ rendrait le code mal lisible. De plus, les prototypes de Service ne verront pas de membres privés - seul le public sera à leur disposition:

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'

Pour résumer, utiliser Factory est plus pratique. As Factory n'a pas ces inconvénients. Je recommanderais de l'utiliser par défaut.

Andrew Krook
la source
Cette réponse pose plusieurs problèmes. Tout d'abord, cet article illustre le concept Javascript de la portée lexicale plutôt que le fonctionnement des services AngularJS. Deuxièmement, le contexte d'appel myapp.service(...)est complètement absent. Où est new Service()censé être appelé, dans la fonction de service ou à l'endroit où le service est injecté. La troisième inscription n'est tout simplement pas possible dans le contexte de myapp.service ('Service', function() {...}).
lanoxx
2

Même quand ils disent que tous les services et usines sont uniques, je ne suis pas d'accord à 100% avec cela. Je dirais que les usines ne sont pas des singletons et c'est le point de ma réponse. Je penserais vraiment au nom qui définit chaque composant (Service / Factory), je veux dire:

Une usine, car n'est pas un singleton, vous pouvez en créer autant que vous le souhaitez lorsque vous injectez, cela fonctionne donc comme une usine d'objets. Vous pouvez créer une fabrique d'une entité de votre domaine et travailler plus confortablement avec ces objets qui pourraient être comme un objet de votre modèle. Lorsque vous récupérez plusieurs objets, vous pouvez les mapper dans ces objets et cela peut agir comme une autre couche entre le DDBB et le modèle AngularJs.Vous pouvez ajouter des méthodes aux objets afin de vous orienter un peu plus vers les objets de votre application AngularJs.

Pendant ce temps, un service est un singleton, donc nous ne pouvons en créer qu'un seul, peut-être pas créer, mais nous n'avons qu'une seule instance lorsque nous injectons dans un contrôleur, donc un service fournit plus comme un service commun (appels de repos, fonctionnalité ..) aux contrôleurs.

Sur le plan conceptuel, vous pouvez penser que les services fournissent un service, les usines peuvent créer plusieurs instances (objets) d'une classe

francisco J Jimenez Garcia
la source
0

Prestations de service

Syntaxe : module.service ('serviceName', fonction); Résultat : lorsque vous déclarez serviceName comme argument injectable, vous recevrez la référence de fonction réelle transmise à 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', fonction);

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 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 invoquant 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? Encore un peu flou sur celui-ci.

Nishant Upadhyay
la source
0

Peut utiliser les deux comme vous le souhaitez : créer un objet ou simplement accéder aux fonctions des deux


Vous pouvez créer un nouvel objet à partir du service

app.service('carservice', function() {
    this.model = function(){
        this.name = Math.random(22222);
        this.price = 1000;
        this.colour = 'green';
        this.manufacturer = 'bmw';
    }
});

.controller('carcontroller', function ($scope,carservice) { 
    $scope = new carservice.model();
})

Remarque :

  • le service par défaut renvoie un objet et non une fonction constructeur.
  • C'est pourquoi la fonction constructeur est définie sur la propriété this.model.
  • En raison de ce service retournera un objet, mais mais mais à l'intérieur de cet objet se trouvera une fonction constructeur qui sera utilisée pour créer un nouvel objet;

Vous pouvez créer un nouvel objet en usine

app.factory('carfactory', function() {
    var model = function(){
        this.name = Math.random(22222);
        this.price = 1000;
        this.colour = 'green';
        this.manufacturer = 'bmw';
    }
    return model;
});

.controller('carcontroller', function ($scope,carfactory) { 
    $scope = new carfactory();
})

Remarque :

  • usine par défaut renvoie la fonction constructeur et non l'objet.
  • C'est pourquoi un nouvel objet peut être créé avec la fonction constructeur.

Créer un service pour accéder simplement à des fonctions simples

app.service('carservice', function () {
   this.createCar = function () {
       console.log('createCar');
   };
   this.deleteCar = function () {
       console.log('deleteCar');
   };
});

.controller('MyService', function ($scope,carservice) { 
    carservice.createCar()
})

Créer une usine pour accéder simplement à des fonctions simples

app.factory('carfactory', function () {
    var obj = {} 
        obj.createCar = function () {
            console.log('createCar');
        };
       obj.deleteCar = function () {
       console.log('deleteCar');
    };
});

.controller('MyService', function ($scope,carfactory) { 
    carfactory.createCar()
})

Conclusion :

  • vous pouvez utiliser les deux comme vous le souhaitez, que ce soit pour créer un nouvel objet ou simplement pour accéder à des fonctions simples
  • Il n'y aura aucun impact sur les performances, en utilisant l'un sur l'autre
  • Les deux sont des objets singleton et une seule instance est créée par application.
  • Être une seule instance partout où leur référence est passée.
  • Dans la documentation angulaire, l' usine est appelée service et le service est également appelé service .
vijay
la source
0

L'usine et le service sont la méthode la plus utilisée. La seule différence entre eux est que la méthode Service fonctionne mieux pour les objets qui ont besoin d'une hiérarchie d'héritage, tandis que Factory peut produire des primitives et des fonctions JavaScript.

La fonction Provider est la méthode principale et toutes les autres ne sont que du sucre syntaxique. Vous n'en avez besoin que si vous créez un morceau de code réutilisable qui nécessite une configuration globale.

Il existe cinq méthodes pour créer des services: Value, Factory, Service, Provider et Constant. Vous pouvez en savoir plus sur ce service angulaire ici , cet article explique toutes ces méthodes avec des exemples de démonstration pratiques.

.

user3114005
la source