Services vs. Factories en Angular

EDIT 2016. Notez que ce post, qui est un repost d’un post de 2015, concerne Angular 1. Je ne fais plus de frontend, donc aucune garantie que ce post est pertinent pour Angular 2 ;).

Un de mes camarades de classe Hack Reactor et moi avons récemment construit un calculateur de traitement de l’hypertension artérielle pour Moxe Health, une entreprise passionnante de Rock Health qui construit un système d’intégration de base de données et une API qui permettra à tout développeur d’accéder aux dossiers médicaux électroniques de n’importe quel hôpital du réseau de Moxe. J’ai hâte de parler de Moxe et du projet dans un autre billet. Nous avons construit le front-end de l’application en Angular, un puissant framework frontal avec liaison de données et d’autres fonctionnalités impressionnantes. Une chose qui était déroutante était de savoir quand utiliser les services ou les usines. Stack Overflow a un bon fil sur la différence entre les deux, mais il laisse de côté certaines analogies qui, je pense, sont utiles aux développeurs qui cimentent encore leurs connaissances en Javascript.

Dans ce post, vous allez apprendre la différence entre les deux.

TLDR – les usines et les services ont à peu près la même fonctionnalité en termes de capacité à instancier et à encapsuler des méthodes et des propriétés, un peu comme les modèles d’instanciation fonctionnelle et d’instanciation pseudoclassique ont des capacités similaires. Il n’y a pas de préférence dans la communauté Angular pour l’utilisation de l’un ou l’autre. Les recettes de fabrique et de service ne sont que du sucre syntaxique au-dessus de la recette de fournisseur. Donc la question que vous devriez vous poser n’est généralement pas « dois-je utiliser des usines ou des services ? », c’est « dois-je utiliser l’instantanéité fonctionnelle ou l’instanciation pseudoclassique ? ». »

Outre cette compréhension de haut niveau, la différence la plus significative est qu’en raison de la différence dans leurs modèles d’instanciation, les fabriques peuvent retourner des primitives et des fonctions, mais pas les services.

Primitives, fonctions et objets, oh my!

Voyez cette JSFiddle. Crédit à Epokk pour avoir fourni la plupart du code. J’ai fait quelques modifications qui, encore une fois, aident vraiment les développeurs nouveaux à Angular à percer la différence ici. Si vous ne connaissez pas JSFiddle, c’est un outil qui vous permet de tester facilement les interactions entre vos fichiers javascript, html et css. Ainsi, vous pouvez jouer avec le code, et il n’écrasera pas le code original dans le lien.

Le service et la fabrique dans cet exemple ont la même fonctionnalité de retourner la chaîne « Hello World ! ». La différence est la façon dont ils le font.

Le service instancie un objet et affecte la fonction qui renvoie « Hello World ! » à la propriété « sayHello » de cet objet:

this.sayHello = function() { return "Hello, World!" };

La méthode est ensuite invoquée dans le contrôleur : helloWorldFromService.sayHello().

La fabrique renvoie une fonction qui renvoie « Hello World ! »:

return function() { return "Hello, World!" };

La fonction est ensuite invoquée dans le contrôleur : helloWorldFromFactory(). Notez comment la référence de la factory pointe sur la fonction retournée, plutôt que sur la propriété d’un objet dont la valeur est une fonction, comme dans l’exemple du service. Un service ne pourrait jamais faire cela, car un service doit instancier un objet vide dont la référence dans le corps de la fonction du service est ‘this’. Les services retournent toujours des objets.

Voici la partie des usines qui peut prêter à confusion. La fabrique peut aussi retourner un objet qui a une méthode ‘sayHello’, un peu comme le service :

return { sayHello: function() { return "Hello, World!" } };

Que vous invoqueriez dans le contrôleur exactement comme vous invoqueriez la fonction sayHello du service : helloWorldFromFactory.sayHello().

Ce dernier format de fabrique est utile lorsque vous voulez avoir de multiples méthodes dans une fabrique :

return { sayHello: function() { return "Hello, World!" }, sayGoodbye: function() { return "Goodbye, World!" } };

Encore, la clé ici est de ne pas être pris dans le fait que vous codez en Angular, et de se rappeler que les différences entre les services et les fabriques sont pour la plupart les mêmes que les différences entre l’instanciation pseudoclassique et l’instanciation fonctionnelle.

Code source pour les curieux

Voici le code source d’Angular, démontrant que les services &fabriques sont superposés à la fonctionnalité plus générale des providers:

//provider function provider(name, provider_) { assertNotHasOwnProperty(name, 'service'); if (isFunction(provider_) || isArray(provider_)) { provider_ = providerInjector.instantiate(provider_); } if (!provider_.$get) { throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name); } return providerCache = provider_; } //factory function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); } //service function service(name, constructor) { return factory(name, ); }

Les deux services et les deux fabriques créent des singletons. Des modèles d’héritage fonctionnels de base vs. pseudoclassiques ici. Le factory renvoie ce que le factoryFn renvoie.

Le service renvoie une instance d’une pseudo-classe. Le constructeur de la pseudo-classe est passé au constructeur de service d’Angular, service(). Le fait que le constructeur soit passé au service constructeur de service (return $injector.instantiate(constructor)) peut prêter à confusion, mais il suffit de penser à cela comme return new constructor().

Happy coding!

Leave a Reply