Služby vs. továrny v Angularu
EDIT 2016. Všimněte si, že tento příspěvek, který je repostem příspěvku z roku 2015, se týká Angularu 1. Frontendem se už nezabývám, takže nezaručuji, že je tento příspěvek relevantní pro Angular 2 ;).
Jeden z mých spolužáků z Hack Reactoru a já jsme nedávno vytvořili kalkulačku pro léčbu vysokého krevního tlaku pro Moxe Health, zajímavou společnost Rock Health, která buduje systém integrace databází a rozhraní API, které umožní každému vývojáři přístup k elektronickým lékařským záznamům kterékoli nemocnice v síti Moxe. O společnosti Moxe a tomto projektu budu s nadšením hovořit v dalším příspěvku. Front-end aplikace jsme vytvořili v Angularu, výkonném front-endovém frameworku s datovými vazbami a dalšími úžasnými funkcemi. Jednou z věcí, která byla matoucí, bylo, kdy použít služby vs. továrny. Na Stack Overflow je dobré vlákno o rozdílu mezi nimi, ale vynechává některé analogie, které jsou podle mě užitečné pro vývojáře, kteří si teprve upevňují své znalosti Javascriptu.
V tomto příspěvku se dozvíte, jaký je mezi nimi rozdíl.
TLDR – továrny a služby mají v podstatě stejnou funkčnost, pokud jde o jejich schopnost instancovat a zapouzdřovat metody a vlastnosti, podobně jako mají podobné schopnosti funkční instanciační a pseudoklasické instanciační vzory. V komunitě Angularu neexistuje žádná preference pro používání jednoho nebo druhého. Recepty Factory a Service jsou pouze syntaktickým cukrem nad receptem Provider. Otázka, kterou byste si měli klást, tedy obvykle nezní „mám používat továrny nebo služby?“, ale „mám používat funkční instantaci nebo pseudoklasickou instanciaci?“.“
Kromě tohoto vysokoúrovňového pochopení je nejvýznamnějším rozdílem to, že v důsledku rozdílu v instanciačních vzorcích mohou továrny vracet primitiva a funkce, ale služby ne.
Primitiva, funkce a objekty, ach jo!
Podívejte se na tento JSFiddle. Za poskytnutí většiny kódu děkuji Epokkovi. Provedl jsem několik úprav, které opět opravdu pomohou vývojářům, kteří s Angularem teprve začínají, aby se zde vrtali v rozdílech. Pokud jste v JSFiddle nováčci, jedná se o nástroj, který vám umožní snadno testovat interakce mezi soubory javascript, html a css. Můžete si tedy pohrát s kódem, aniž by došlo k přepsání původního kódu v odkazu.
Obě služby i továrna v tomto příkladu mají stejnou funkčnost – vracejí řetězec „Hello World!“. Rozdíl je v tom, jak to dělají.
Služba instancuje objekt a přiřadí funkci, která vrací „Hello World!“, do vlastnosti „sayHello“ tohoto objektu:
this.sayHello = function() { return "Hello, World!" };
Metoda je pak volána v kontroléru: helloWorldFromService.sayHello().
Továrna vrací funkci, která vrací „Hello World!“:
return function() { return "Hello, World!" };
Tato funkce je pak vyvolána v kontroléru: helloWorldFromFactory(). Všimněte si, že odkaz továrny ukazuje na vrácenou funkci, nikoli na vlastnost objektu, jehož hodnotou je funkce, jako v příkladu služby. Služba by to nikdy nemohla udělat, protože služba musí instancovat prázdný objekt, jehož odkazem v těle funkce služby je ‚this‘. Služby vždy vracejí objekty.
Tady je část faktorů, která může být matoucí. Továrna může také vrátit objekt, který má metodu ‚sayHello‘, podobně jako služba:
return { sayHello: function() { return "Hello, World!" } };
kterou byste v kontroléru vyvolali přesně tak, jako byste vyvolali funkci sayHello služby: helloWorldFromFactory.sayHello().
Posledně jmenovaný formát továrny je užitečný, když chcete mít v továrně více metod:
return { sayHello: function() { return "Hello, World!" }, sayGoodbye: function() { return "Goodbye, World!" } };
Znovu připomínám, že klíčem k úspěchu je nenechat se strhnout tím, že programujete v Angularu, a pamatovat si, že rozdíly mezi službami a továrnami jsou z velké části stejné jako rozdíly mezi pseudoklasickou instancí a funkční instancí.
Zdrojový kód pro zvědavce
Tady je zdrojový kód jazyka Angular, který ukazuje, že služby & továrny jsou navrstveny na obecnější funkci poskytovatelů:
//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, ); }
Obě služby i továrny vytvářejí singletony. Základní funkční vs. pseudoklasické vzory dědičnosti zde. Továrna vrací to, co vrací factoryFn.
Služba vrací instanci pseudotřídy. Konstruktor pseudotřídy je předán konstruktoru služby service() systému Angular. To, že se konstruktor předává službě service builder service (return $injector.instantiate(constructor)), může být matoucí, ale prostě si to představte jako return new constructor().
Šťastné kódování!
Leave a Reply