To pomogło mi zrozumieć różnicę dzięki postowi na blogu Pascala Prechta.
Usługa to metoda w module, która przyjmuje nazwę i funkcję, która definiuje usługę. Możesz wstrzykiwać i używać tej konkretnej usługi w innych komponentach, takich jak kontrolery, dyrektywy i filtry. Fabryka jest metodą na module, a także wymaga nazwy i funkcji, która definiuje fabrykę. Możemy również wstrzykiwać i używać go w taki sam sposób, jak w przypadku usługi.
Obiekty utworzone przy użyciu nowego używają wartości właściwości prototypowej funkcji konstruktora jako ich prototypu, więc znalazłem kod Angular, który wywołuje Object.create (), który moim zdaniem jest funkcją konstruktora usług, gdy zostanie utworzona instancja. Jednak funkcja fabryczna jest tak naprawdę tylko funkcją, która jest wywoływana, dlatego musimy zwrócić literał obiektu dla fabryki.
Oto kod kątowy 1.5, który znalazłem dla fabryki:
var needsRecurse = false;
var destination = copyType(source);
if (destination === undefined) {
destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
needsRecurse = true;
}
Kątowy fragment kodu źródłowego dla funkcji factory ():
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
}
Pobiera przekazaną nazwę i funkcję fabryczną i zwraca dostawcę o tej samej nazwie, który ma metodę $ get, która jest naszą funkcją fabryczną. Ilekroć pytasz wtryskiwacza o konkretną zależność, w zasadzie pyta on odpowiedniego dostawcę o instancję tej usługi, wywołując metodę $ get (). Dlatego $ get () jest wymagany podczas tworzenia dostawców.
Oto kątowy kod 1.5 dla usługi.
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
Okazuje się, że kiedy wywołujemy service (), tak naprawdę wywołuje factory ()! Jednak nie tylko przekazuje fabryczną funkcję konstruktora usług. Przekazuje także funkcję, która prosi wtryskiwacz o utworzenie obiektu przez dany konstruktor.
Innymi słowy, jeśli wstrzykniemy gdzieś MyService, to co dzieje się w kodzie to:
MyServiceProvider.$get(); // return the instance of the service
Aby ponownie utworzyć go ponownie, usługa wywołuje fabrykę, która jest metodą $ get () na odpowiednim dostawcy. Ponadto $ injector.instantiate () jest metodą, która ostatecznie wywołuje Object.create () z funkcją konstruktora. Dlatego używamy „tego” w usługach.
W przypadku ES5 nie ma znaczenia, z którego korzystamy: service () lub factory (), zawsze jest wywoływana fabryka, która tworzy dostawcę naszych usług.
Możesz zrobić dokładnie to samo z usługami. Usługa jest jednak funkcją konstruktora, która nie uniemożliwia nam zwracania literałów obiektowych. Abyśmy mogli pobrać nasz kod serwisowy i napisać go w taki sposób, że zasadniczo robi dokładnie to samo, co nasza fabryka, lub innymi słowy, możesz napisać usługę jako fabryka, aby zwrócić obiekt.
Dlaczego większość ludzi zaleca korzystanie z fabryk zamiast usług? To najlepsza odpowiedź, jaką widziałem, pochodząca z książki Pawła Kozłowskiego: Mastering Web Application Development with AngularJS.
Metoda fabryczna jest najczęstszym sposobem wprowadzania obiektów do systemu wstrzykiwania zależności AngularJS. Jest bardzo elastyczny i może zawierać wyrafinowaną logikę tworzenia. Ponieważ fabryki są funkcjami regularnymi, możemy również skorzystać z nowego zakresu leksykalnego do symulacji zmiennych „prywatnych”. Jest to bardzo przydatne, ponieważ możemy ukryć szczegóły implementacji danej usługi. ”