Widziałem zarówno angular.factory (), jak i angular.service () używane do deklarowania usług; nie mogę jednak znaleźć angular.service
nigdzie w oficjalnej dokumentacji.
Jaka jest różnica między tymi dwiema metodami?
Którego należy użyć do czego (zakładając, że robią różne rzeczy)?
angularjs
angular-services
Jakub
źródło
źródło
Odpowiedzi:
Miałem problem z owinięciem głowy tą koncepcją, dopóki nie przedstawiłem jej w ten sposób:
Usługa : funkcja , którą piszesz, będzie nowa :
Fabryka : wywołana funkcja (konstruktor) zostanie wywołana :
To, co z tym zrobisz, zależy od ciebie, ale istnieją pewne użyteczne wzorce ...
Na przykład napisanie funkcji usługi w celu ujawnienia publicznego interfejsu API:
Lub za pomocą funkcji fabrycznej w celu ujawnienia publicznego interfejsu API:
Lub użycie funkcji fabryki do zwrócenia konstruktora:
Którego użyć? ...
Możesz osiągnąć to samo za pomocą obu. Jednak w niektórych przypadkach fabryka zapewnia nieco większą elastyczność w tworzeniu wstrzyknięć z prostszą składnią. Dzieje się tak, ponieważ chociaż myInjectedService musi zawsze być obiektem, myInjectedFactory może być obiektem, odwołaniem do funkcji lub dowolną wartością. Na przykład, jeśli napisałeś usługę do stworzenia konstruktora (jak w poprzednim przykładzie powyżej), musiałaby zostać utworzona instancja w następujący sposób:
co jest prawdopodobnie mniej pożądane niż to:
(Należy jednak przede wszystkim zachować ostrożność przy stosowaniu tego typu wzorca, ponieważ nowe obiekty w kontrolerach tworzą trudne do śledzenia zależności, które trudno wyśmiewać w celu przetestowania. Lepiej mieć usługę zarządzającą kolekcją obiektów dla niż używać
new()
chytrego).Jeszcze jedno, wszyscy są Singletonami ...
Należy również pamiętać, że w obu przypadkach kątowe pomaga zarządzać singletonem. Bez względu na to, gdzie i ile razy wstrzykujesz swoją usługę lub funkcję, otrzymasz takie samo odniesienie do tego samego obiektu lub funkcji. (Z wyjątkiem sytuacji, gdy fabryka po prostu zwraca wartość taką jak liczba lub łańcuch. W takim przypadku zawsze otrzymasz tę samą wartość, ale nie odwołanie).
źródło
new fn()
, więc muszą zwrócić instancję.Po prostu…
źródło
Oto podstawowe różnice:
Usługi
Składnia:
module.service( 'serviceName', function );
Wynik: deklarując serviceName jako argument do wstrzyknięcia, otrzymasz instancję funkcji przekazanej do
module.service
.Użycie: Może być przydatny do udostępniania funkcji narzędziowych, które można wywołać, po prostu dołączając
( )
do wstrzykniętego odwołania do funkcji. Można go również uruchomić zinjectedArg.call( this )
podobnym.Fabryki
Składnia:
module.factory( 'factoryName', function );
Wynik: deklarując nazwę fabryki jako argument do wstrzyknięcia, otrzymasz wartość zwracaną przez wywołanie przekazanego odwołania do funkcji
module.factory
.Użycie: Może być przydatny do zwracania funkcji „klasy”, którą można następnie zmienić w celu utworzenia instancji.
Oto przykład korzystania z usług i fabryki . Przeczytaj więcej o AngularJS Service vs Factory .
Możesz także sprawdzić dokumentację AngularJS i podobne pytanie na temat przepełnienia stosu mylone z usługą a fabryką .
źródło
$providers
cały czas.this.myFunc = function(){}
w swojej usłudze (oszczędza ci to pisania kodu, aby utworzyć obiekt tak, jakbyś miał do czynienia z fabryką ).TL; DR
1) Gdy używasz fabryki , tworzysz obiekt, dodajesz do niego właściwości, a następnie zwraca ten sam obiekt. Po przekazaniu tej fabryki do kontrolera właściwości tego obiektu będą teraz dostępne w tym kontrolerze za pośrednictwem fabryki.
2) Gdy używasz usługi , Angular tworzy ją za kulisami ze słowem kluczowym „new”. Z tego powodu dodasz właściwości do „tego”, a usługa zwróci „to”. Po przekazaniu usługi do kontrolera właściwości „this” będą teraz dostępne na tym kontrolerze za pośrednictwem usługi.
Non TL; DR
1)
Fabryki to najpopularniejszy sposób tworzenia i konfigurowania usługi. Naprawdę niewiele więcej niż mówi TL; DR. Wystarczy utworzyć obiekt, dodać do niego właściwości, a następnie zwrócić ten sam obiekt. Następnie, po przekazaniu fabryki do kontrolera, te właściwości obiektu będą teraz dostępne w tym kontrolerze przez fabrykę. Bardziej obszerny przykład znajduje się poniżej.
Teraz wszelkie właściwości, które dołączamy do „usługi”, będą dostępne, gdy przekażemy „myFactory” do naszego kontrolera.
Dodajmy teraz trochę „prywatnych” zmiennych do naszej funkcji zwrotnej. Nie będą one bezpośrednio dostępne z poziomu kontrolera, ale w końcu skonfigurujemy metody getter / setter dla „service”, aby móc zmienić te „prywatne” zmienne w razie potrzeby.
Tutaj zauważysz, że nie przypisujemy tych zmiennych / funkcji do „usługi”. Po prostu tworzymy je w celu późniejszego wykorzystania lub modyfikacji.
Teraz, gdy nasze zmienne pomocnicze / prywatne i funkcja są już na miejscu, dodajmy pewne właściwości do obiektu „service”. Cokolwiek zastosujemy w „usłudze”, będziemy mogli bezpośrednio używać w dowolnym kontrolerze, w którym przekazujemy „myFactory”.
Stworzymy metody setArtist i getArtist, które po prostu zwrócą lub ustawią artystę. Stworzymy również metodę, która wywoła interfejs API iTunes z naszym utworzonym adresem URL. Ta metoda zwróci obietnicę, która spełni się, gdy dane wrócą z interfejsu API iTunes. Jeśli nie miałeś dużego doświadczenia w korzystaniu z obietnic w Angular, bardzo polecam głębokie zanurzenie się w nich.
Poniżej setArtist akceptuje wykonawcę i umożliwia ustawienie wykonawcy. getArtist zwraca artystę callItunes najpierw wywołuje makeUrl () w celu zbudowania adresu URL, którego będziemy używać z naszym żądaniem $ http. Następnie ustawia obiekt obietnicy, wysyła żądanie $ http z naszym ostatnim adresem URL, a ponieważ $ http zwraca obietnicę, jesteśmy w stanie wywołać .success lub .error po naszej prośbie. Następnie wypełniamy naszą obietnicę za pomocą danych iTunes lub odrzucamy ją komunikatem „Wystąpił błąd”.
Teraz nasza fabryka jest kompletna. Jesteśmy teraz w stanie wstrzyknąć „myFactory” do dowolnego kontrolera, a następnie będziemy mogli wywoływać nasze metody, które podłączyliśmy do naszego obiektu usługi (setArtist, getArtist i callItunes).
W powyższym kontrolerze wprowadzamy usługę „myFactory”. Następnie ustawiamy właściwości naszego obiektu $ scope, które pochodzą z danych z „myFactory”. Jedynym trudnym kodem powyżej jest to, że nigdy wcześniej nie dotykałeś obietnic. Ponieważ callItunes zwraca obietnicę, jesteśmy w stanie użyć metody .then () i ustawić wartość $ scope.data.artistData tylko wtedy, gdy nasza obietnica zostanie wypełniona danymi iTunes. Zauważysz, że nasz kontroler jest bardzo „cienki”. Wszystkie nasze logiczne i trwałe dane znajdują się w naszym serwisie, a nie w naszym kontrolerze.
2) Usługa
Być może największą rzeczą, o której należy wiedzieć podczas tworzenia Usługi, jest to, że jest ona tworzona za pomocą słowa kluczowego „new”. Dla ciebie guru JavaScript powinien dać ci dużą wskazówkę dotyczącą natury kodu. Dla tych z ograniczonym doświadczeniem w JavaScript lub dla tych, którzy nie są zbyt dobrze zaznajomieni z tym, co faktycznie robi „nowe” słowo kluczowe, przejrzyjmy niektóre podstawy JavaScript, które ostatecznie pomogą nam zrozumieć naturę Usługi.
Aby naprawdę zobaczyć zmiany, które następują po wywołaniu funkcji słowem kluczowym „new”, utwórzmy funkcję i wywołaj ją słowem kluczowym „new”, a następnie pokażmy, co robi tłumacz, gdy zobaczy słowo kluczowe „new”. Oba wyniki końcowe będą takie same.
Najpierw stwórzmy naszego Konstruktora.
Jest to typowa funkcja konstruktora JavaScript. Teraz za każdym razem, gdy wywołujemy funkcję Osoba za pomocą słowa kluczowego „new”, „to” zostanie powiązane z nowo utworzonym obiektem.
Dodajmy teraz metodę do prototypu naszej Osoby, aby była dostępna w każdej instancji naszej „klasy” Osoby.
Teraz, ponieważ umieszczamy funkcję sayName na prototypie, każda instancja Person będzie mogła wywołać funkcję sayName, aby zaalarmować nazwę tej instancji.
Teraz, gdy mamy prototyp konstruktora Person i funkcję sayName na jego prototypie, utwórzmy instancję Person, a następnie wywołaj funkcję sayName.
Cały kod do tworzenia konstruktora Person, dodawania funkcji do jego prototypu, tworzenia instancji Person, a następnie wywoływania funkcji na prototypie wygląda tak.
Teraz spójrzmy na to, co się właściwie dzieje, gdy używasz słowa kluczowego „new” w JavaScript. Pierwszą rzeczą, którą powinieneś zauważyć, jest to, że po użyciu „new” w naszym przykładzie jesteśmy w stanie wywołać metodę (sayName) na „tyler” tak, jakby to był obiekt - to dlatego, że tak jest. Po pierwsze wiemy, że nasz konstruktor Person zwraca obiekt, bez względu na to, czy widzimy to w kodzie, czy nie. Po drugie, wiemy, że ponieważ nasza funkcja sayName znajduje się na prototypie, a nie bezpośrednio na instancji Person, obiekt, który zwraca funkcja Person, musi delegować do swojego prototypu podczas nieudanych wyszukiwań. Mówiąc prościej, kiedy wywołujemy tyler.sayName () interpreter mówi „OK, przejrzę właśnie utworzony obiekt„ tyler ”, zlokalizuj funkcję sayName, a następnie wywołaj ją. Chwileczkę, nie widzę tego tutaj - widzę tylko imię i wiek, pozwól mi sprawdzić prototyp. Tak, wygląda na to, że jest na prototypie, nazwijmy to ”.
Poniżej znajduje się kod wyjaśniający, co tak naprawdę robi „nowe” słowo kluczowe w JavaScript. Jest to w zasadzie przykład kodu powyższego akapitu. Umieściłem „widok tłumacza” lub sposób, w jaki tłumacz widzi kod w notatkach.
Mając już wiedzę o tym, co tak naprawdę robi „nowe” słowo kluczowe w JavaScript, tworzenie Usługi w Angular powinno być łatwiejsze do zrozumienia.
Najważniejszą rzeczą do zrozumienia podczas tworzenia Usługi jest świadomość, że Usługi są tworzone za pomocą słowa kluczowego „new”. Łącząc tę wiedzę z naszymi powyższymi przykładami, powinieneś teraz wiedzieć, że będziesz przypisywać swoje właściwości i metody bezpośrednio do „tego”, który następnie zostanie zwrócony z samej Usługi. Spójrzmy na to w akcji.
W przeciwieństwie do tego, co pierwotnie zrobiliśmy z przykładem Factory, nie musimy tworzyć obiektu, a następnie zwracać go, ponieważ, jak wspomniano wiele razy wcześniej, użyliśmy słowa kluczowego „new”, aby interpreter utworzył ten obiekt, zlecając mu to prototyp, a następnie zwróć go nam bez konieczności wykonywania pracy.
Po pierwsze, stwórzmy naszą funkcję „prywatną” i pomocniczą. Powinno to wyglądać bardzo znajomo, ponieważ zrobiliśmy dokładnie to samo z naszą fabryką. Nie wyjaśnię, co robi tutaj każda linia, ponieważ zrobiłem to w przykładzie fabrycznym. Jeśli jesteś zdezorientowany, przeczytaj ponownie przykład fabryczny.
Teraz dołączymy wszystkie nasze metody, które będą dostępne w naszym kontrolerze do „tego”.
Teraz, podobnie jak w naszej fabryce, setArtist, getArtist i callItunes będą dostępne w dowolnym kontrolerze, do którego przekazujemy myService. Oto kontroler myService (który jest prawie dokładnie taki sam jak nasz kontroler fabryczny).
Jak wspomniałem wcześniej, kiedy naprawdę zrozumiesz, co robi „nowość”, usługi są prawie identyczne z fabrykami w Angular.
źródło
Wskazówka jest w nazwie
Usługi i fabryki są do siebie podobne. Oba dadzą pojedynczy obiekt, który można wstrzyknąć w inne obiekty, dlatego często są używane zamiennie.
Są przeznaczone do stosowania semantycznego do implementacji różnych wzorców projektowych.
Usługi służą do wdrażania wzorca usługi
Wzorzec usługi to taki, w którym aplikacja jest podzielona na logicznie spójne jednostki funkcjonalności. Przykładem może być akcesorium API lub zestaw logiki biznesowej.
Jest to szczególnie ważne w Angular, ponieważ modele Angular są zazwyczaj tylko obiektami JSON pobranymi z serwera, dlatego potrzebujemy miejsca, w którym można umieścić logikę biznesową.
Oto na przykład usługa Github. Wie, jak rozmawiać z Githubem. Wie o adresach URL i metodach. Możemy wstrzyknąć go do kontrolera, który wygeneruje i zwróci obietnicę.
Fabryki wdrażają wzór fabryczny
Z drugiej strony fabryki mają wdrożyć wzór fabryczny. Wzorzec fabryczny w tym, w którym używamy funkcji fabrycznej do generowania obiektu. Zwykle możemy tego użyć do budowy modeli. Oto fabryka, która zwraca konstruktora autora:
Wykorzystamy to w następujący sposób:
Pamiętaj, że fabryki również zwracają singletony.
Fabryki mogą zwrócić konstruktor
Ponieważ fabryka po prostu zwraca obiekt, może zwrócić dowolny typ obiektu, w tym funkcję konstruktora, jak widzimy powyżej.
Fabryki zwracają obiekt; usługi są odnawialne
Kolejną różnicą techniczną jest sposób, w jaki składają się usługi i fabryki. Zostanie dodana funkcja usługi do generowania obiektu. Wywołana zostanie funkcja fabryczna i zwróci obiekt.
Oznacza to, że w usłudze dołączamy do „tego”, który w kontekście konstruktora będzie wskazywał na obiekt w budowie.
Aby to zilustrować, oto ten sam prosty obiekt utworzony za pomocą usługi i fabryki:
źródło
Author
powinien znajdować się parametr wtryskiwaczaPerson
.Wszystkie odpowiedzi tutaj wydają się dotyczyć serwisu i fabryki, i jest to ważne, ponieważ o to pytano. Ale ważne jest też, aby pamiętać, że istnieje wiele innych, w tym
provider()
,value()
iconstant()
.Kluczem do zapamiętania jest to, że każdy z nich jest szczególnym przypadkiem drugiego. Każdy specjalny przypadek w dół łańcucha pozwala robić to samo z mniejszym kodem. Każdy z nich ma także dodatkowe ograniczenia.
Aby zdecydować, kiedy użyć, który po prostu widzisz, który pozwala ci robić, co chcesz, w mniejszym stopniu kodu. Oto obraz ilustrujący ich podobieństwo:
Aby uzyskać pełny podział krok po kroku i szybki przegląd tego, kiedy użyć każdego z nich, możesz odwiedzić wpis na blogu, z którego otrzymałem ten obraz:
http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/
źródło
app.factory ('fn', fn) vs. app.service ('fn', fn)
Budowa
W przypadku fabryk Angular wywoła funkcję, aby uzyskać wynik. Jest to wynik, który jest buforowany i wstrzykiwany.
W przypadku usług Angular wywoła funkcję konstruktora, wywołując new . Skonstruowana funkcja jest buforowana i wstrzykiwana.
Realizacja
Fabryki zwykle zwracają literał obiektu, ponieważ zwracana wartość jest wprowadzana do kontrolerów, bloków uruchamiania, dyrektyw itp.
Funkcje serwisowe zazwyczaj niczego nie zwracają. Zamiast tego wykonują inicjalizację i udostępniają funkcje. Funkcje mogą również odwoływać się do „tego”, ponieważ został on utworzony przy użyciu „nowego”.
Wniosek
Jeśli chodzi o korzystanie z fabryk lub usług, oba są bardzo podobne. Są one wstrzykiwane do kontrolerów, dyrektyw, bloków uruchomieniowych itp. I używane w kodzie klienta w podobny sposób. Oba są również singletonami - co oznacza, że ta sama instancja jest dzielona między wszystkie miejsca, w których wstrzykiwana jest usługa / fabryka.
Więc co wolisz? Oba - są tak podobne, że różnice są banalne. Jeśli wybierzesz jedną z drugiej, pamiętaj tylko, jak są one zbudowane, abyś mógł je odpowiednio zaimplementować.
źródło
Spędziłem trochę czasu próbując zrozumieć różnicę.
I myślę, że funkcja fabryki używa wzorca modułu, a funkcja usługi używa standardowego wzorca konstruktora skryptu Java.
źródło
Wzorzec fabryczny jest bardziej elastyczny, ponieważ może zwracać funkcje i wartości oraz obiekty.
Wzorzec serwisowy IMHO nie ma większego sensu, ponieważ wszystko, co robi, można równie łatwo zrobić w fabryce. Wyjątkami mogą być:
Prawdopodobnie wzorzec usługi jest nieco lepszym sposobem na utworzenie nowego obiektu z punktu widzenia składni, ale jego utworzenie jest również bardziej kosztowne. Inni wskazywali, że angular używa „nowego” do utworzenia usługi, ale nie jest to do końca prawdą - nie jest w stanie tego zrobić, ponieważ każdy konstruktor usługi ma inną liczbę parametrów. To, co faktycznie robi kąt, to użycie wewnętrznego wzorca fabrycznego do zawinięcia funkcji konstruktora. Następnie wykonuje sprytną manipulację, symulując „nowy” operator javascript, wywołując konstruktora ze zmienną liczbą argumentów do wstrzyknięcia - ale możesz pominąć ten krok, jeśli bezpośrednio użyjesz wzorca fabrycznego, co bardzo nieznacznie zwiększy wydajność twojego kod.
źródło
function MyFactory(dep1) { var $$foo = 'bar', factory = {}; Object.defineProperties(factory.prototype, { foo: { value: $$foo } }); return factory; }
function MyService(dep1) { var $$foo = 'bar'; Object.defineProperties(MyService.prototype, { foo: { value: $$foo } }); }
Podczas gdy zarówno MyFactory, jak i MyService używają prototypu, MyFactory nadal ma wpływ na wydajność, ponieważ musi skonstruować zwracany obiekt. W obu przykładach mają osoby prywatne, ale w MyService nie ma względnie żadnej różnicy w wydajności.MyFactory(someArgument)
(np$http()
.). Nie jest to możliwe z usługą jak chcesz być odwołującego konstruktora:MyService(someArgument)
.