Services vs. Factories in Angular

EDIT 2016. Huomaa, että tämä postaus, joka on repostaus vuodelta 2015 olevasta postauksesta, koskee Angular 1:tä. En tee enää frontendiä, joten ei ole mitään takeita siitä, että tämä postaus on relevantti Angular 2:n kannalta ;).

Yksi Hack Reactor -luokkatoverini ja minä rakensimme hiljattain korkean verenpaineen hoitolaskurin Moxe Healthille, jännittävälle Rock Health -yhtiölle, joka rakentaa tietokantaintegraatiojärjestelmää ja API:ta, jonka avulla kuka tahansa kehittäjä pääsee käsiksi minkä tahansa sairaalan sähköisiin potilastietoihin Moxen verkossa. Olen innoissani puhuessani Moxesta ja hankkeesta toisessa postauksessa. Rakensimme sovelluksen front-endin Angularilla, joka on tehokas front-end-kehys, jossa on datan sitominen ja muita mahtavia ominaisuuksia. Yksi asia, joka oli hämmentävä, oli se, milloin käyttää palveluita vs. tehtaita. Stack Overflow’ssa on hyvä säie näiden kahden välisestä erosta, mutta se jättää pois joitakin analogioita, jotka ovat mielestäni hyödyllisiä kehittäjille, jotka vielä sementoivat Javascript-tietämystään.

Tässä postauksessa opit näiden kahden eron.

TLDR – tehtailla ja palveluilla on melko lailla sama toiminnallisuus niiden kyvyssä instantioida ja kapseloida metodeja ja ominaisuuksia, aivan kuten funktionaalisella instantiointimallilla (functional instantiation pattern) ja pseudoklassisella (pseudoclassical) instantiointimallilla (pseudoclassical instantiation pattern) on samanlaisia kykyjä. Angular-yhteisö ei suosi jommankumman käyttöä. Tehdas- ja palvelureseptit ovat vain syntaktista sokeria tarjoajareseptin päällä. Joten kysymys, joka sinun pitäisi esittää itsellesi, ei yleensä ole ”pitäisikö minun käyttää tehtaita vai palveluita?” vaan ”pitäisikö minun käyttää funktionaalista instantiointia vai pseudoklassista instantiointia?”.”

Tämän korkean tason ymmärryksen lisäksi merkittävin ero on se, että niiden instantiointimallien eron seurauksena tehtaat voivat palauttaa primitiivejä ja funktioita, mutta palvelut eivät.

Primitiivejä, funktioita ja objekteja, voi hyvänen aika!

Katso tämä JSFiddle. Kiitokset Epokkille suurimman osan koodin tarjoamisesta. Tein pari muutosta, jotka taas todella auttavat Angulariin uusia kehittäjiä porautumaan eroihin tässä. Jos olet uusi JSFiddle, se on työkalu, jonka avulla voit helposti testata vuorovaikutusta javascript, html ja css-tiedostojen välillä. Voit siis leikkiä koodilla, eikä se korvaa linkin alkuperäistä koodia.

Kummallakin palvelulla ja tehtaalla on tässä esimerkissä sama toiminnallisuus palauttaa merkkijono ”Hello World!”. Ero on siinä, miten ne sen tekevät.

Palvelu instantioi objektin ja määrittää funktion, joka palauttaa ”Hello World!”, kyseisen objektin ”sayHello”-ominaisuuteen:

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

Tämän jälkeen metodia kutsutaan kontrollerissa: helloWorldFromService.sayHello().

Tehdas palauttaa funktion, joka palauttaa ”Hello World!”:

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

Funktiota kutsutaan sitten ohjaimessa: helloWorldFromFactory(). Huomaa, kuinka tehtaan viittaus osoittaa palautettuun funktioon, eikä sellaisen objektin ominaisuuteen, jonka arvo on funktio, kuten palvelun esimerkissä. Palvelu ei voisi koskaan tehdä näin, koska palvelun täytyy luoda tyhjä objekti, jonka viite palvelun funktiorungossa on ’this’. Palvelut palauttavat aina objekteja.

Tässä on se osa tehtaista, joka voi olla hämmentävä. Tehdas voi myös palauttaa objektin, jolla on metodi ’sayHello’, aivan kuten palvelulla:

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

Jota kutsuisit kontrollerissa täsmälleen samalla tavalla kuin palvelun sayHello-funktiota: helloWorldFromFactory.sayHello().

Jälkimmäinen tehdasmuoto on hyödyllinen silloin, kun haluat, että tehtaassa on useita metodeja:

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

Tänäänkin avainasemassa on se, ettet jää kiinni siitä, että koodaat Angularissa, ja että muistat, että palveluiden ja tehtaiden väliset erot ovat suurimmaksi osaksi samat kuin pseudoklassisen instantioinnin ja funktionaalisen instantioinnin erot.

Lähdekoodi uteliaille

Tässä Angularin lähdekoodi, joka havainnollistaa, että palvelut &tehtaat on kerrostettu yleisemmän providers-ominaisuuden päälle:

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

Kaikki palvelut ja tehtaat luovat singletoneja. Perus funktionaaliset vs. pseudoklassiset periytymismallit tässä. Factory palauttaa mitä factoryFn palauttaa.

Palvelu palauttaa pseudoluokan instanssin. Pseudo-luokan konstruktori välitetään Angularin palvelunrakentajalle service(). Se, että konstruktori välitetään palvelunrakentajan palvelulle (return $injector.instantiate(constructor)) voi olla hämmentävää, mutta ajattele vain, että se on return new constructor().

Happy coding!

Leave a Reply