Tjenester vs. fabrikker i Angular

EDIT 2016. Bemærk, at dette indlæg, som er et repost af et indlæg fra 2015, handler om Angular 1. Jeg laver ikke frontend længere, så der er ingen garantier for, at dette indlæg er relevant for Angular 2 ;).

En af mine Hack Reactor-klassekammerater og jeg byggede for nylig en beregner til behandling af forhøjet blodtryk for Moxe Health, et spændende Rock Health-firma, der er ved at opbygge et databaseintegrationssystem og API, der vil give enhver udvikler adgang til de elektroniske patientjournaler fra ethvert hospital i Moxes netværk. Jeg glæder mig til at tale om Moxe og projektet i et andet indlæg. Vi byggede appens front-end i Angular, et kraftfuldt front-end framework med databinding og andre fantastiske funktioner. En ting, der var forvirrende, var, hvornår vi skulle bruge services vs. factories. Stack Overflow har en god tråd om forskellen mellem de to, men den udelader nogle analogier, som jeg mener er nyttige for udviklere, der stadig cementerer deres Javascript-viden.

I dette indlæg vil du lære forskellen mellem de to.

TLDR – factories og services har stort set samme funktionalitet med hensyn til deres evne til at instantiere og enscapsulate metoder og egenskaber, ligesom funktionel instantiering og pseudoklassiske instantieringsmønstre har lignende evner. Der er ingen præference i Angular-fællesskabet for at bruge det ene eller det andet. Factory- og serviceopskrifter er blot syntaktisk sukker på toppen af provider-opskriften. Så det spørgsmål, du bør stille dig selv, er normalt ikke “skal jeg bruge factories eller services?” Det er “skal jeg bruge funktionel instantiering eller pseudoklassisk instantiering?”

Afhængig af denne forståelse på højt niveau er den væsentligste forskel, at som følge af forskellen i deres instantieringsmønstre kan factories returnere primitives og funktioner, men det kan services ikke.

Primitives, funktioner og objekter, oh my!

Kig på denne JSFiddle. Kredit til Epokk for at levere det meste af koden. Jeg har foretaget et par ændringer, der igen virkelig hjælper udviklere, der er nye til Angular, til at bore ned i forskellen her. Hvis du er ny til JSFiddle, er det et værktøj, der giver dig mulighed for nemt at teste interaktioner mellem dine javascript-, html- og css-filer. Så du kan lege med koden, og det vil ikke overskrive den oprindelige kode i linket.

Både tjenesten og fabrikken i dette eksempel har den samme funktionalitet, nemlig at returnere strengen “Hello World!”. Forskellen er, hvordan de gør det:

Tjenesten instantierer et objekt og tildeler funktionen, der returnerer “Hello World!”, til “sayHello”-egenskaben for dette objekt:

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

Metoden påkaldes derefter i controlleren: helloWorldFromService.sayHello().

Fabrikken returnerer en funktion, der returnerer “Hello World!”:

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

Funktionen påkaldes derefter i controlleren: helloWorldFromFactory(). Bemærk, hvordan fabrikkens reference peger på den returnerede funktion i stedet for på egenskaben ved et objekt, hvis værdi er en funktion, som i serviceeksemplet. En tjeneste kunne aldrig gøre dette, fordi en tjeneste skal instantiere et tomt objekt, hvis reference i tjenestefunktionens krop er “this”. Tjenester returnerer altid objekter.

Her er den del af factories, som kan være forvirrende. Fabrikken kan også returnere et objekt, der har en metode ‘sayHello’, ligesom tjenesten:

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

Hvilket du ville påberåbe dig i controlleren, præcis som du ville påberåbe dig tjenestens sayHello-funktion: helloWorldFromFactory.sayHello().

Det sidstnævnte fabriksformat er nyttigt, når du ønsker at have flere metoder i en fabrik:

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

Snart igen er det vigtigste her, at du ikke bliver fanget af, at du koder i Angular, og at du husker på, at forskellene mellem tjenester og fabrikker for det meste er de samme som forskellene mellem pseudoklassisk instantiering og funktionel instantiering.

Kildekode til de nysgerrige

Her er Angular-kildekoden, der viser, at services & factories er lagt oven på den mere generelle providers-funktion:

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

Både service og factory skaber singletons. Grundlæggende funktionelle vs. pseudoklassiske arvelighedsmønstre her. Fabrikken returnerer det, som factoryFn returnerer.

Tjenesten returnerer en instans af en pseudoklasse. Pseudoklassens konstruktør sendes til Angular’s service builder service(). Det kan være forvirrende, at konstruktøren sendes til service builder service (return $injector.instantiate(constructor)), men tænk på det som return new constructor().

Happy coding!

Leave a Reply