W tym rozdziale zajmujemy się tematem, który dla każdego kto styka się z AngularJS po raz pierwszy,
spędza sen z powiek. Mowa tutaj o usługach. W AngularJS mamy kilka typów usług, które
pozwalają nam zająć się różnymi kategoriami zagadnień w ramach szeroko pojętej definicji tego słowa. W
tym rozdziale skupimy się na tych usługach, które są szczególnie pomocne w kontekście budowy warstwy
przetwarzania danych:
- Serwis (Service)
- Fabryka (Factory)
Istotną cechą obiektów usług jest to, że są one tworzone raz i tylko raz, aż do momentu ponowego
przeładowania strony. Niezależnie od tego ile wykonamy przełączeń między widokami, to o ile
fizycznie pozostaniemy na jednej stronie, to dane przechowywane w usługach będą ciągle pamiętane.
Serwis (Service)
Zarówno serwis (service) jak i fabryka (factory) mogą nam posłużyć do budowy frontendowej warstwy
przetwarzania danych. Za ich pomocą będziemy wysyłać żądania HTTP, przyjmować odpowiedzi do tych żądań oraz wykonywać
algorytmy operujące na danych dostarczanych z widoków przez kontrolery. Dzięki możliwości wstrzykiwania wykorzystamy tutaj również serwisy
wbudowane w AngularJS, takie jak na przykład serwis
$http.
Serwis i fabryka są ze sobą mocno powiązane. Zagłębiając się w kod AngularJS zauważymy, że podczas
uruchamiania,
funkcja
serwisu
za każdym razem woła funkcję
fabryki
. Tworząc serwis i podając
funkcję konstruującą
powinniśmy mieć zatem świadomość, że zostanie ona wykorzystana przez fabrykę w celu stworzenia
obiektu:
Tak to wygląda gdy zajrzymy do kodu frameworka. Co jednak z naszym kodem? Jak stworzyć pierwszy
serwis? W tym celu musimy wykorzystać funkcję
service, która zarejestruje naszą usługę w module:
Jako pierwszy parametr - oznaczający nazwę serwisu - przyjmiemy
AppaFormService
. Drugim parametrem funkcji
service
będzie
funkcja konstruująca, której wywołanie doprowadzi do stworzenia obiektu serwisu. Tak jak pisaliśmy wcześniej, samym
uruchomieniem funkcji konstruującej zajmie się fabryka.
W tym miejscu pojawia się pytanie. Skoro wywołanie serwisu jest redundantne, to czy nie lepiej jest
ominąć ten krok i wywołać fabrykę bezpośrednio? Oczywiście możemy tak robić i jest to nawet
preferowane przez nas podejście, natomiast wydaje się, że to czy wybierzemy serwis czy fabrykę jest
tak naprawdę sprawą drugorzędną. Wybór taki może być podyktowany tym, że po prostu w którymś
formacie zapisu czujemy się trochę lepiej. Na zasadzie co kto lubi.
Fabryka (Factory)
Fabryka to typ usługi, która albo jest uruchamiana przez service (co pokazaliśmy wyżej), albo może
być też wywołana bezpośrednio przez nas samych. Wtedy tworzymy ją - podobnie jak service -
korzystając z odpowiedniej funkcji dostępnej w ramach modułu. Używamy do tego funkcji o nazwie
factory
:
Charakterystyczną cechą fabryki odróżniającą ją od serwisu jest to, że funkcja użyta do jej
tworzenia nie jest funkcją konstruującą. Jest to regularna funkcja Javascript, w
której możemy tworzyć inne
funkcje realizujące algorytmy związane z przetwarzaniem danych.
Najważniejsze jednak jest to, że musimy pamiętać o zwróceniu rezultatu działania tej funkcji w
postaci
obiektu. Jest to dokładnie taki obiekt jaki byłby tutaj stworzony gdyby fabryka była uruchamiana z poziomu
serwisu, tyle że teraz tworzymy go literalnie (zamiast jawnego wywołania funkcji konstruującej).
Tak więc ostatecznie dochodzimy do wniosku, że obiekt stworzony wcześniej przez funkcję konstruującą
w serwisie i przekazaną do fabryki:
jest równoważny w stosunku do obiektu tworzonego przez nas literalnie bezpośrednio w samej fabryce:
Podsumowanie
Opisywany w tym rozdziale temat nie jest łatwy do zrozumienia i z pewnością może nieco zniechęcać do głębszej analizy. Nie zmienia to jednak faktu, że
po kilkukrotnym przeczytaniu naszych rozważań, a być może też skorzystaniu z innych źródeł (podanych na dole strony) stanie się on znacznie bardziej czytelny.
Warto go przeanalizować, aby zrozumieć "pudełkową" konstrukcję usług serwis, fabryka i dostawca (service, factory, provider).
O tej ostatniej nie wspomnieliśmy w tym rozdziale, gdyż różni się ona nieco w kontekście użycia od obu powyższych i dlatego poświęciliśmy jej osobny (kolejny) rozdział.
Nasza rekomendacja
Od samego początku, gdy tylko AngularJS zaczął zyskiwać na popularności, programiści sprzeczali
się co do tego, które z powyższych rozwiązań jest lepsze i co tak naprawdę powinno wykonywać
naszą usługę. Patrząc na nazewnictwo bardziej naturalne wydaje się użycie rozwiązania typu
service, niemniej factory też ma swoje niewątpliwe zalety, jak choćby możliwość wykonania kodu
jeszcze przed utworzeniem obiektu usługi (we wspomnianej regularnej funkcji Javascript).
Warto mieć na uwadze, że jeśli w przyszłości będziemy chcieli migrować z ES5 na ES6, to wówczas
będziemy tworzyć klasy nazywane już faktycznie serwisami i może warto od razu przyzwyczajać się
do takiego nazewnictwa. Chociaż i tutaj można spojrzeć na sprawę z drugiej strony. Z czysto
pragmatycznego punktu widzenia wysiłek programistyczny przenoszenia kodu z factory czy z service
będzie porównywalny. Wybór pozostawiamy Wam.
Używamy w StartAPPa
W aplikacji do budowy warstwy usług wykorzystujemy factory. Za każdym razem gdy kontroler chce
pobrać lub wysłać dane odwołuje się do obiektu usługi, która posiada wstrzyknięte odpowiednie
mechanizmy do wykonywania zadań. W bieżącym rozdziale przedstawiliśmy fragment usługi działającej
w ramach modułu
Formularz Zaawansowany
.
Pełna wersja kodu tej usługi jest odpowiedzialna za pobieranie z serwera i przekazanie do
kontrolera danych początkowych oraz umożliwia zapis wszystkich danych formularza. Dodatkowo dane
słownikowe zapamiętywanie są w cache'u, aby uniknąć regularnego pobierania ich przy każdej
próbie wywołania funkcji pobierającej.
Linki
https://docs.angularjs.org/guide/providers#factory-recipe
https://docs.angularjs.org/guide/providers#service-recipe
https://www.quora.com/What-is-the-difference-between-a-factory-and-service-in-AngularJS-and-when-should-each-be-used