Verwirrt über Service vs Factory


618

So wie ich es verstehe, gebe ich in einer Fabrik ein Objekt zurück, das in eine Steuerung injiziert wird. Wenn ich mich in einem Dienst befinde, beschäftige ich mich mit dem Objektthis etwas und nichts zurückgebe.

Ich ging davon aus, dass ein Dienst immer ein Singleton und ein neues Fabrikobjekt war in jeden Controller eingefügt wird. Wie sich jedoch herausstellt, ist ein Factory-Objekt auch ein Singleton?

Beispielcode zur Demonstration:

var factories = angular.module('app.factories', []);
var app = angular.module('app',  ['ngResource', 'app.factories']);

factories.factory('User', function () {
  return {
    first: 'John',
    last: 'Doe'
  };
});

app.controller('ACtrl', function($scope, User) {
  $scope.user = User;
});

app.controller('BCtrl', function($scope, User) {
  $scope.user = User;
});

Beim Wechsel user.firstin ACtrles stellt sich heraus , dass user.firstin BCtrlebenfalls geändert, zBUser ein Singleton ist?

Meine Annahme war, dass eine neue Instanz in einen Controller mit einer Fabrik eingefügt wurde?


4
Neben "module.service" und "module.factory" gibt es zwei weitere Möglichkeiten, Dienste in AngularJS zu erstellen. Weitere Informationen finden Sie im Blogbeitrag: " So erstellen Sie (Singleton-) AngularJS-Dienste auf vier verschiedene Arten "
Emil van Galen

Mögliches Duplikat von angle.service vs angle.factory
Kaushal28

Antworten:


600

Alle Winkeldienste sind Singletons :

Dokumente (siehe Dienste als Singletons ): https://docs.angularjs.org/guide/services

Schließlich ist es wichtig zu erkennen, dass alle Angular-Dienste Anwendungs-Singletons sind. Dies bedeutet, dass es pro Injektor nur eine Instanz eines bestimmten Dienstes gibt.

Grundsätzlich ist der Unterschied zwischen Service und Werk wie folgt:

app.service('myService', function() {

  // service is just a constructor function
  // that will be called with 'new'

  this.sayHello = function(name) {
     return "Hi " + name + "!";
  };
});

app.factory('myFactory', function() {

  // factory returns an object
  // you can run some code before

  return {
    sayHello : function(name) {
      return "Hi " + name + "!";
    }
  }
});

Schauen Sie sich diese Präsentation über $ liefern an: http://slides.wesalvaro.com/20121113/#/

Diese Folien wurden in einem der AngularJs-Meetups verwendet: http://blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html


13
Siehe auch stackoverflow.com/questions/15666048/…, in dem die Unterschiede zwischen Service, Werk und Bereitstellung erläutert werden.
Mark Rajcok

31
Das offizielle Dokument indirekt [sic! nicht genug klar] impliziert, dass selbst wenn Sie Service mit Factory definieren, dieser nur einmal erstellt wird. Mit anderen Worten, es wird NICHT erneut gemäß Referenz (Injektionspunkt) erstellt - wie auch immer Sie es nennen. Beide Möglichkeiten führen zu einer Singleton-Instanz pro Injektor.
Honzajde

3
Sie sagen, "Service ist nur eine Konstruktorfunktion, die mit 'new' aufgerufen wird", aber ich denke, das ist irreführend. Ich glaube nicht, dass es hinter den Kulissen neu heißt, ich denke, der Entwickler ist dafür verantwortlich, newes aufzurufen .
Tim Kindberg

5
@nfiniteloop, überprüfen Sie den Quellcode in der Nähe von Zeile 3574. Fabriken sind die $ get-Methode eines Anbieters, und Dienste generieren Fabriken mit einer Methode, die $ injor.instantiate für die bereitgestellte Funktion aufruft und dann new aufruft. ( Siehe Dokumente )
Citizenslave

14
Ich hatte den Eindruck, dass ein Dienst ein Singleton war, den Sie verwendet haben, indem Sie einen Verweis darauf erhalten haben. Und dass eine Fabrik ein Singleton war, der jedes Mal ein neues Objekt zurückgab. Das heißt, ein Service würde Ihnen ein "Auto" geben und alles in Ihrem Projekt würde dieses Auto verwenden. Während eine Fabrik Ihnen jedes Mal ein neues Auto geben würde, wenn Sie die Fabrik aufrufen. Einer war ein Singleton, der einen Singleton zurückgab, und einer war ein Singleton, der ein Objekt zurückgab. Kann jemand erklären? Es hilft nicht, alles als Singleton zu bezeichnen, da es sich auf mehrere Dinge beziehen kann.
user2483724

380

Für mich kam die Offenbarung, als mir klar wurde, dass sie alle auf die gleiche Weise funktionieren: indem sie etwas einmal ausführen, den Wert speichern, den sie erhalten, und dann denselben gespeicherten Wert abhusten, wenn sie durch Abhängigkeitsinjektion referenziert werden.

Sagen wir, wir haben:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

Der Unterschied zwischen den drei ist:

  1. aDer gespeicherte Wert stammt aus dem Laufen fn, mit anderen Worten:fn()
  2. bDer gespeicherte Wert stammt von newing fn, mit anderen Worten:new fn()
  3. cDer gespeicherte Wert ergibt sich daraus, dass zuerst eine Instanz newabgerufen fnund dann eine $getMethode der Instanz ausgeführt wird

Das heißt, es gibt so etwas wie ein Cache-Objekt innerhalb des Winkels, dessen Wert jeder Injektion nur einmal zugewiesen wird, wenn sie das erste Mal injiziert wurden und wo:

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

Aus diesem Grund verwenden wir thisin Diensten und definieren athis.$get in Anbietern.

Hoffe das hilft.


54
Endlich eine vernünftige Erklärung. Angular ist verrückt und so schlimm, dass es weh tut.
Osiris

8
Dies sollte die akzeptierte Antwort sein, da sie tatsächlich die Frage beantwortet, WARUM Fabriken, Dienste und Anbieter Singleton-Werte zurückgeben. Die anderen Antworten erklären den Unterschied zwischen Fabriken, Diensten und Anbietern, berühren jedoch niemals den Singleton-Aspekt.
wmock

3
Ich mag das ... Wenn ich die tausend Satzzeilen eines anderen Bloggers lese, schaffe ich es nur, die Fabrik zu verstehen. Aber ich lese das ... ich verstehe alle 3.
tsohtan

@osiris Ich stimme zu. Ich mag es nicht. Es fühlt sich einfach so verdammt eng an, dass meine Zähne knirschen.
Thomas

2
Sie müssen also eine Implementierung von $ get bereitstellen, wenn Sie Anbieter verwenden?
Victor

95

Live-Beispiel

Beispiel "Hallo Welt"

mit factory/ service/ provider:

var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!"
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!"
        }
    };
});

//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {
    // In the provider function, you cannot inject any
    // service or factory. This can only be done at the
    // "$get" method.

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});


function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {

    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}​

57

Es gibt auch eine Möglichkeit, eine Konstruktorfunktion zurückzugeben, sodass Sie in Fabriken wie folgt neue Klassen zurückgeben können:

function MyObjectWithParam($rootScope, name) {
  this.$rootScope = $rootScope;
  this.name = name;
}
MyObjectWithParam.prototype.getText = function () {
  return this.name;
};

App.factory('MyObjectWithParam', function ($injector) {
  return function(name) { 
    return $injector.instantiate(MyObjectWithParam,{ name: name });
  };
}); 

Sie können dies also in einem Controller tun, der MyObjectWithParam verwendet:

var obj = new MyObjectWithParam("hello"),

Das vollständige Beispiel finden Sie hier:
http://plnkr.co/edit/GKnhIN?p=preview

Und hier die Google-Gruppenseiten, auf denen darüber gesprochen wurde:
https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ


Ich habe Probleme mit der Minimierung anhand Ihres Beispiels. Weißt du, wie ich das kommentieren soll?
Pål

2
Ja, es gibt eine minimierte Notation für Angular. Es sollte App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); ungefähr so aussehen: Lesen Sie hier mehr darüber: docs.angularjs.org/tutorial/step_05
JustGoscha

4
Warum sollten Sie dies tun, wenn Sie .servicestattdessen verwenden können?
Flup

Ich hatte den gleichen Gedanken @flup. @justgoscha, gibt es einen Vorteil ( wahrgenommen? ) der Verwendung .factoryim Gegensatz zu .service?
Xandercoded

5
Ich denke, weil ein Dienst ein Singleton ist . Was ich hier konstruiert habe, ist im Grunde eine Klasse, die neu ist. Sie können also so etwas wie eine Autowerkstatt haben und dann machen new Car('BMW')und new Car('Ford')und sie teilen nicht die gleichen Variablen und alles.
JustGoscha

51

Hier sind die Hauptunterschiede:

Dienstleistungen

Syntax: module.service( 'serviceName', function );

Ergebnis: Wenn Sie serviceName als injizierbares Argument deklarieren, erhalten Sie die Instanz einer Funktion, an die übergeben wird module.service.

Verwendung: Kann nützlich sein, um Dienstprogrammfunktionen freizugeben , die zum Aufrufen nützlich sind, indem einfach () an die Referenz der injizierten Funktion angehängt wird. Könnte auch mit injectedArg.call( this )oder ähnlich ausgeführt werden.

Fabriken

Syntax: module.factory( 'factoryName', function );

Ergebnis: Wenn factoryName als injizierbare Argument erklärt werden Sie zur Verfügung gestellt werden Wert, der durch den Aufruf der Funktion Referenz zurückgegeben wird weitergegeben module.factory.

Verwendung: Kann nützlich sein, um eine 'Klasse' zurückzugeben. Klassen' Funktion zurückzugeben, die dann neu erstellt werden kann, um Instanzen zu erstellen.

Überprüfen Sie auch die AngularJS-Dokumentation und ähnliche Fragen zum Stackoverflow, die hinsichtlich Service und Factory verwirrt sind .

Hier ist ein Beispiel für die Verwendung von Services und Factory . Lesen Sie mehr über AngularJS Service vs Factory .


6
Das macht für mich Sinn. Die Fabrik gibt den Entwurf zum Erstellen neuer Objekte zurück.

27

Neben der ersten Antwort ist .service () meiner Meinung nach für Personen gedacht, die ihren Code in einem objektorientierteren Stil (C # / Java) geschrieben haben (mit diesem Schlüsselwort und Instanziieren des Objekts über die Prototyp- / Konstruktorfunktion).

Factory ist für Entwickler gedacht, die Code schreiben, der für Javascript / funktionalen Codierungsstil natürlicher ist.

Schauen Sie sich den Quellcode der .service- und .factory-Methode in angle.js an - intern rufen alle die Provider-Methode auf:

  function provider(name, provider_) {
    if (isFunction(provider_)) {
      provider_ = providerInjector.instantiate(provider_);
    }
    if (!provider_.$get) {
      throw Error('Provider ' + name + ' must define $get factory method.');
    }
    return providerCache[name + providerSuffix] = provider_;
  }

  function factory(name, factoryFn) { \
    return provider(name, { $get: factoryFn }); 
  }

  function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

25

Ganz einfach:

.service - registrierte Funktion wird als Konstruktor aufgerufen (auch bekannt als 'newed')

.factory - registrierte Funktion wird als einfache Funktion aufgerufen

Beide werden einmal aufgerufen, was zu einem Singleton-Objekt führt, das in andere Komponenten Ihrer App eingefügt wird.


6
Ja. Machen wir die Dinge nicht komplizierter als sie wirklich sind
flup

20

Alle Anbieter arbeiten gleich. Die verschiedenen Methoden service, factory,provider nur lassen Sie die gleiche Sache in weniger Code auszuführen.

PS Es gibt auch valueundconstant .

Jeder Sonderfall entlang der Kette beginnt mit providerund endet mitvalue hat eine zusätzliche Einschränkung. Um sich zwischen ihnen zu entscheiden, müssen Sie sich fragen, wie Sie mit weniger Code erreichen können, was Sie wollen.

Hier ist ein Bild, das dir zeigt, was ich meine:

Geben Sie hier die Bildbeschreibung ein

Sie können eine Aufschlüsselung und ein Referenzhandbuch für den Blog-Beitrag erstellen, von dem ich dieses Bild erhalten habe:

http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


Services sollen Singleton sein, aber wie kommt es, dass es Singleton ist, wenn jedes Mal, wenn ich es injiziere, eine neue Instanz erstellt wird?
Ankur Marwaha

1
@AnkurMarwaha Eine neue Instanz wird nicht jedes Mal erstellt, sondern nur einmal erstellt und von AngularJS zwischengespeichert. Dies gilt unabhängig davon, ob Sie einen Anbieter, eine Fabrik, einen Dienst usw. verwenden. Sie können dies mit console.log()mehreren Controllern bestätigen und in diese einspeisen.
Luis Perez

Luis, Ihr Kommentar widerspricht der akzeptierten Antwort, wie es heißt: Schließlich ist es wichtig zu erkennen, dass alle Angular-Dienste Anwendungs-Singletons sind. Dies bedeutet, dass es pro Injektor nur eine Instanz eines bestimmten Dienstes gibt.
Ankur Marwaha

@AnkurMarwaha vielleicht verstehe ich etwas falsch. Sie haben zitiert: "Es ist wichtig zu wissen, dass alle Angular-Dienste Anwendungs-Singletons sind." Die Tatsache, dass es sich um Singletons handelt, bedeutet, dass sie nur einmal erstellt werden. Was ich gesagt habe "Eine neue Instanz wird nicht jedes Mal erstellt, sondern nur einmal erstellt und zwischengespeichert ...". Können Sie genauer darauf hinweisen, wo Sie den Konflikt sehen?
Luis Perez

1
Ah, ich sehe die Verwirrung. Der "Injektor" ist ein Objekt im Winkel. Es ist verantwortlich für die "Injektion". Beispiel: Wenn die Steuerung zum ersten Mal ausgeführt wird, überprüft der "Injektor" die Parameter und injiziert jeden einzelnen. Es gibt nur einen "Injektor" für Ihre gesamte App. Sobald der Injektor eine bestimmte Fabrik oder Dienstleistung erstellt, behält er eine Instanz bei und verwendet sie wieder - daher der Singleton. Es gibt also nur einen Injektor pro App und nur eine Instanz eines bestimmten Dienstes pro Injektor. Die meisten Angular-Anwendungen haben nur eine App, also einen Injektor, also eine Instanz eines Dienstes, einer Steuerung usw.
Luis Perez

13

Hier sind einige weitere Beispiele für Dienstleistungen im Vergleich zu Fabriken, die hilfreich sein können, um den Unterschied zwischen ihnen zu erkennen. Grundsätzlich hat ein Dienst "neu ..." aufgerufen, er ist bereits instanziiert. Eine Fabrik wird nicht automatisch instanziiert.

Grundlegende Beispiele

Gibt ein Klassenobjekt mit einer einzelnen Methode zurück

Hier ist ein Dienst, der eine einzige Methode hat:

angular.service('Hello', function () {
  this.sayHello = function () { /* ... */ };
});

Hier ist eine Factory, die ein Objekt mit einer Methode zurückgibt:

angular.factory('ClassFactory', function () {
  return {
    sayHello: function () { /* ... */ }
  };
});

Geben Sie einen Wert zurück

Eine Fabrik, die eine Liste von Zahlen zurückgibt:

angular.factory('NumberListFactory', function () {
  return [1, 2, 3, 4, 5];
});

console.log(NumberListFactory);

Ein Dienst, der eine Liste von Nummern zurückgibt:

angular.service('NumberLister', function () {
  this.numbers = [1, 2, 3, 4, 5];
});

console.log(NumberLister.numbers);

Die Ausgabe ist in beiden Fällen gleich, die Liste der Zahlen.

Erweiterte Beispiele

"Klassen" -Variablen mit Fabriken

In diesem Beispiel definieren wir eine CounterFactory, sie erhöht oder dekrementiert einen Zähler und Sie können die aktuelle Anzahl abrufen oder abrufen, wie viele CounterFactory-Objekte erstellt wurden:

angular.factory('CounterFactory', function () {
  var number_of_counter_factories = 0; // class variable

  return function () {
    var count = 0; // instance variable
    number_of_counter_factories += 1; // increment the class variable

    // this method accesses the class variable
    this.getNumberOfCounterFactories = function () {
      return number_of_counter_factories;
    };

    this.inc = function () {
      count += 1;
    };
    this.dec = function () {
      count -= 1;
    };
    this.getCount = function () {
      return count;
    };
  }

})

Wir verwenden das CounterFactory, um mehrere Zähler zu erstellen. Wir können auf die Klassenvariable zugreifen, um zu sehen, wie viele Zähler erstellt wurden:

var people_counter;
var places_counter;

people_counter = new CounterFactory();
console.log('people', people_counter.getCount());
people_counter.inc();
console.log('people', people_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());

places_counter = new CounterFactory();
console.log('places', places_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());
console.log('counters', places_counter.getNumberOfCounterFactories());

Die Ausgabe dieses Codes lautet:

people 0
people 1
counters 1
places 0
counters 2
counters 2

Es ist ein nützliches Beispiel. Number_of_counter_factories ist wie ein Meta-Attribut der CounterFactory-Klasse, richtig? Ich verstehe, dass dieses Beispiel auf einen Dienst replizierbar ist (sagen Sie mir, wenn ich falsch liege). Was wäre der semantische Unterschied in diesem Fall?
Geoom

Nützliches Beispiel! Dies bedeutet im Grunde, dass Sie in einer Fabrik diese zusätzliche Abstraktionsebene haben können, die in einem Dienst nicht vorhanden wäre. Was auch immer zurückgegeben wird, eine neue Instanz davon wird zurückgegeben, wenn 'new' verwendet wird. Alle Variablen, die nicht im Rückgabeblock deklariert sind, sind Singleton. Habe ich es richtig gesagt?
Swanidhi

@Swanidhi Grundsätzlich ja, Sie können Variablen deklarieren, die in der Fabrik Singletons sind. Deshalb habe ich sie "Klassen" -Variablen genannt.

13

"Factory" und "Service" sind verschiedene Methoden, um DI (Dependency Injection) im Winkel auszuführen.

Wenn wir also DI mit "service" definieren, wie im folgenden Code gezeigt. Dadurch wird eine neue GLOBAL-Instanz des Objekts "Logger" erstellt und in die Funktion eingefügt.

app.service("Logger", Logger); // Injects a global object

Wenn Sie DI mithilfe einer "Factory" definieren, wird keine Instanz erstellt. Es wird nur die Methode übergeben und später muss der Verbraucher intern Aufrufe an die Factory für Objektinstanzen tätigen.

app.factory("Customerfactory", CreateCustomer);

Unten sehen Sie ein einfaches Bild, das visuell zeigt, wie sich der DI-Prozess für „Service“ von „Factory“ unterscheidet.

Geben Sie hier die Bildbeschreibung ein

Factory sollte verwendet werden, wenn je nach Szenario unterschiedliche Objekttypen erstellt werden sollen. Beispielsweise möchten wir je nach Szenario ein einfaches Objekt "Kunde" oder "Kunde" mit dem Objekt "Adresse" oder "Kunde" mit dem Objekt "Telefon" erstellen. Hier ist eine detaillierte Erklärung dieses Absatzes

Service sollte verwendet werden, wenn Dienstprogramme oder gemeinsam genutzte Funktionen wie Dienstprogramme, Logger, Fehlerbehandlungsprogramme usw. eingefügt werden sollen.


Jede Antwort, die ich auf diese und ähnliche Fragen gesehen habe, spezifiziert den Unterschied in Mechanik und Syntax. Diese Antwort gibt einen echten Grund an, warum Sie eine über die andere auswählen würden. Es ist eine Frage der Semantik und der Blick auf den Namen, den Service oder die Fabrik, kommuniziert ihren Zweck und wie sie verwendet werden.
Joe Mayo

8

Servicestil : ( wahrscheinlich der einfachste ) gibt die eigentliche Funktion zurück: Nützlich für die Freigabe von Dienstprogrammfunktionen, die zum Aufrufen nützlich sind, indem einfach () an die Referenz der injizierten Funktion angehängt wird.

Ein Dienst in AngularJS ist ein Singleton-JavaScript-Objekt, das eine Reihe von Funktionen enthält

var myModule = angular.module("myModule", []);

myModule.value  ("myValue"  , "12345");

function MyService(myValue) {
    this.doIt = function() {
        console.log("done: " + myValue;
    }
}

myModule.service("myService", MyService);
myModule.controller("MyController", function($scope, myService) {

    myService.doIt();

});

Factory- Stil: ( komplizierter, aber ausgefeilter ) Gibt den Rückgabewert der Funktion zurück: Instanziieren Sie ein Objekt wie new Object () in Java.

Factory ist eine Funktion, die Werte schafft. Wenn ein Service, eine Steuerung usw. einen Wert benötigt, der von einer Fabrik eingespeist wird, erstellt die Fabrik den Wert bei Bedarf. Nach der Erstellung wird der Wert für alle Dienste, Controller usw. wiederverwendet, für die eine Injektion erforderlich ist.

var myModule = angular.module("myModule", []);

myModule.value("numberValue", 999);

myModule.factory("myFactory", function(numberValue) {
    return "a value: " + numberValue;
})  
myModule.controller("MyController", function($scope, myFactory) {

    console.log(myFactory);

});

Provider- Stil: ( vollständige, konfigurierbare Version ) gibt die Ausgabe der $ get-Funktion der Funktion zurück: Konfigurierbar.

Anbieter in AngularJS ist die flexibelste Form der Fabrik, die Sie erstellen können. Sie registrieren einen Anbieter mit einem Modul wie mit einem Dienst oder einer Fabrik, außer dass Sie stattdessen die Funktion provider () verwenden.

var myModule = angular.module("myModule", []);

myModule.provider("mySecondService", function() {
    var provider = {};
    var config   = { configParam : "default" };

    provider.doConfig = function(configParam) {
        config.configParam = configParam;
    }

    provider.$get = function() {
        var service = {};

        service.doService = function() {
            console.log("mySecondService: " + config.configParam);
        }

        return service;
    }

    return provider;
});

myModule.config( function( mySecondServiceProvider ) {
    mySecondServiceProvider.doConfig("new config param");
});

myModule.controller("MyController", function($scope, mySecondService) {

    $scope.whenButtonClicked = function() {
        mySecondService.doIt();
    }

});

src jenkov

<!DOCTYPE html>
    <html ng-app="app">
    <head>
    	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
    	<meta charset=utf-8 />
    	<title>JS Bin</title>
    </head>
    <body ng-controller="MyCtrl">
    	{{serviceOutput}}
    	<br/><br/>
    	{{factoryOutput}}
    	<br/><br/>
    	{{providerOutput}}
    
    	<script>
    
    		var app = angular.module( 'app', [] );
    
    		var MyFunc = function() {
    
    			this.name = "default name";
    
    			this.$get = function() {
    				this.name = "new name"
    				return "Hello from MyFunc.$get(). this.name = " + this.name;
    			};
    
    			return "Hello from MyFunc(). this.name = " + this.name;
    		};
    
    		// returns the actual function
    		app.service( 'myService', MyFunc );
    
    		// returns the function's return value
    		app.factory( 'myFactory', MyFunc );
    
    		// returns the output of the function's $get function
    		app.provider( 'myProv', MyFunc );
    
    		function MyCtrl( $scope, myService, myFactory, myProv ) {
    
    			$scope.serviceOutput = "myService = " + myService;
    			$scope.factoryOutput = "myFactory = " + myFactory;
    			$scope.providerOutput = "myProvider = " + myProv;
    
    		}
    
    	</script>
    
    </body>
    </html>

jsbin

<!DOCTYPE html>
<html ng-app="myApp">
<head>
	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
	<meta charset=utf-8 />
	<title>JS Bin</title>
</head>
<body>
<div ng-controller="MyCtrl">
    {{hellos}}
</div>
	<script>

	var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!"
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!"
        }
    };
});
    
//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});
        

function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
    
    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}
	</script>

</body>
</html>

jsfiddle


2

Der grundlegende Unterschied besteht darin, dass der Anbieter das Festlegen von Werten für Grundelemente (Nichtobjekte), Arrays oder Rückruffunktionen in der werkseitig deklarierten Variablen zulässt. Wenn ein Objekt zurückgegeben wird, muss es explizit deklariert und zurückgegeben werden.

Andererseits kann ein Dienst nur verwendet werden, um die deklarierte Dienstvariable auf ein Objekt zu setzen, sodass die explizite Erstellung und Rückgabe der Objekte vermieden werden kann, während andererseits die Verwendung dieses Schlüsselworts möglich ist.

Oder in kurzen Worten: "Der Anbieter ist eine allgemeinere Form, während der Dienst nur auf Objekte beschränkt ist."


2

So habe ich den Unterschied zwischen ihnen in Bezug auf Designmuster verstanden:

Service : Gibt einen Typ zurück, der neu erstellt wird, um ein Objekt dieses Typs zu erstellen. Wenn Java-Analogie verwendet wird, gibt Service eine Java-Klassendefinition zurück .

Fabrik : Gibt ein konkretes Objekt zurück, das sofort verwendet werden kann. In Java Analogy gibt eine Factory ein Java-Objekt zurück .

Der Teil, der Menschen (einschließlich mich selbst) oft verwirrt, ist, dass, wenn Sie einen Service oder eine Factory in Ihren Code einfügen, diese auf die gleiche Weise verwendet werden können, das, was Sie in Ihrem Code in beiden Fällen erhalten, ein konkretes Objekt ist, das Sie sofort aufrufen können. Dies bedeutet, dass im Falle des Dienstes eckige Anrufe in der Diensterklärung für Sie "neu" sind. Ich denke, das ist ein kompliziertes Konzept.


1

Dies wäre die beste und kurze Antwort, um Service Vs Factory Vs Provider zu verstehen

Quelle : https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/HuZsOsMvKv4J

Hier, was Ben mit einer Demo sagt http://jsbin.com/ohamub/1/edit?html,output

"Der Code enthält Kommentare, die die Hauptunterschiede veranschaulichen, aber ich werde sie hier etwas näher erläutern. Als Hinweis: Ich verstehe das nur. Wenn ich also etwas Falsches sage, lassen Sie es mich bitte wissen.

Dienstleistungen

Syntax : module.service ('serviceName', Funktion);

Ergebnis : Wenn Sie serviceName als injizierbares Argument deklarieren, erhalten Sie die tatsächliche Funktionsreferenz, die an module.service übergeben wird.

Verwendung : Kann nützlich sein, um Dienstprogrammfunktionen freizugeben, die zum Aufrufen nützlich sind, indem einfach () an die Referenz der injizierten Funktion angehängt wird. Könnte auch mit injiziertemArg.call (this) oder ähnlichem ausgeführt werden.

Fabriken

Syntax : module.factory ('factoryName', Funktion);

Ergebnis : Wenn Sie factoryName als injizierbares Argument deklarieren, erhalten Sie den Wert, der durch Aufrufen der an module.factory übergebenen Funktionsreferenz zurückgegeben wird.

Verwendung : Kann nützlich sein, um eine 'Klassen'-Funktion zurückzugeben, die dann neu erstellt werden kann, um Instanzen zu erstellen.

Anbieter

Syntax : module.provider ('providerName', Funktion);

Ergebnis : Wenn Sie providerName als injizierbares Argument deklarieren, erhalten Sie den Wert, der durch Aufrufen der $ get-Methode der an module.provider übergebenen Funktionsreferenz zurückgegeben wird.

Verwendung : Kann nützlich sein, um eine 'Klassen'-Funktion zurückzugeben, die dann neu erstellt werden kann, um Instanzen zu erstellen, für die jedoch vor dem Injizieren eine Konfiguration erforderlich ist. Vielleicht nützlich für Klassen, die projektübergreifend wiederverwendbar sind? Immer noch irgendwie dunstig. "Ben


1

Ich hatte diese Verwirrung für eine Weile und ich versuche mein Bestes, um hier eine einfache Erklärung zu geben. Hoffe das wird helfen!

angular .factoryund angular .servicebeide werden verwendet, um einen Dienst zu initialisieren und auf die gleiche Weise zu arbeiten.

Der einzige Unterschied besteht darin, wie Sie Ihren Service initialisieren möchten.

Beide sind Singletons


var app = angular.module('app', []);


Fabrik

app.factory ( <service name>, <function with a return value>)

Wenn Sie Ihren Service über eine Funktion mit einem Rückgabewert initialisieren möchten , müssen Sie diese factoryMethode verwenden.

z.B

function myService() {
  //return what you want
  var service = {
    myfunc: function (param) { /* do stuff */ }
  }
  return service;
}

app.factory('myService', myService);

Wenn Sie diesen Dienst einspeisen (z. B. an Ihren Controller):

  • Angular ruft Ihre angegebene Funktion (as myService()) auf, um das Objekt zurückzugeben
  • Singleton - wird nur einmal aufgerufen, gespeichert und übergibt dasselbe Objekt.


Bedienung

app.service ( <service name>, <constructor function>)

Wenn Sie Ihren Service über eine Konstruktorfunktion (mit dem thisSchlüsselwort) initialisieren möchten , müssen Sie diese serviceMethode verwenden.

z.B

function myService() {
  this.myfunc: function (param) { /* do stuff */ }
}

app.service('myService', myService);

Wenn Sie diesen Dienst einspeisen (z. B. an Ihren Controller):

  • Angular verwendet newIhre angegebene Funktion (as new myService()), um das Objekt zurückzugeben
  • Singleton - wird nur einmal aufgerufen, gespeichert und übergibt dasselbe Objekt.


HINWEIS: Wenn Sie factorymit <constructor function>oder servicemit verwenden <function with a return value>, funktioniert es nicht.


Beispiele - DEMOs


1

Dies hat mir geholfen, den Unterschied zu verstehen, dank eines Blogposts von Pascal Precht.

Ein Dienst ist eine Methode in einem Modul, die einen Namen und eine Funktion verwendet, die den Dienst definiert. Sie können diesen bestimmten Dienst in andere Komponenten wie Steuerungen, Anweisungen und Filter einfügen und verwenden. Eine Factory ist eine Methode für ein Modul und es werden auch ein Name und eine Funktion verwendet, die die Factory definieren. Wir können es genauso injizieren und verwenden, wie wir es mit dem Service getan haben.

Mit new erstellte Objekte verwenden den Wert der Prototyp-Eigenschaft ihrer Konstruktorfunktion als Prototyp. Daher habe ich den Angular-Code gefunden, der Object.create () aufruft, von dem ich glaube, dass er die Servicekonstruktorfunktion ist, wenn er instanziiert wird. Eine Factory-Funktion ist jedoch nur eine Funktion, die aufgerufen wird. Deshalb müssen wir ein Objektliteral für die Factory zurückgeben.

Hier ist der Winkel-1.5-Code, den ich für die Fabrik gefunden habe:

var needsRecurse = false;
    var destination = copyType(source);

    if (destination === undefined) {
      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
      needsRecurse = true;
    }

Winkelquellcode-Snippet für die Funktion factory ():

 function factory(name, factoryFn, enforce) {
    return provider(name, {
      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
    });
  }

Es nimmt den Namen und die Factory-Funktion, die übergeben wird, und gibt einen Anbieter mit demselben Namen zurück, der eine $ get-Methode hat, die unsere Factory-Funktion ist. Wenn Sie den Injektor nach einer bestimmten Abhängigkeit fragen, fragt er den entsprechenden Anbieter grundsätzlich nach einer Instanz dieses Dienstes, indem er die Methode $ get () aufruft. Aus diesem Grund ist beim Erstellen von Anbietern $ get () erforderlich.

Hier ist der Winkel 1.5 Code für den Service.

function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

Es stellt sich heraus, dass wenn wir service () aufrufen, tatsächlich factory () aufgerufen wird! Es wird jedoch nicht nur unsere Servicekonstruktorfunktion unverändert an das Werk übergeben. Es wird auch eine Funktion übergeben, die den Injektor auffordert, ein Objekt durch den angegebenen Konstruktor zu instanziieren.

Mit anderen Worten, wenn wir MyService irgendwo einfügen, geschieht Folgendes im Code:

MyServiceProvider.$get(); // return the instance of the service

Um es noch einmal zu wiederholen, ruft ein Dienst eine Factory auf, bei der es sich um eine $ get () -Methode des entsprechenden Anbieters handelt. Darüber hinaus ist $ injizor.instantiate () die Methode, die letztendlich Object.create () mit der Konstruktorfunktion aufruft. Deshalb verwenden wir "dies" in Diensten.

Für ES5 spielt es keine Rolle, welche wir verwenden: service () oder factory (), es ist immer eine Factory, die aufgerufen wird und einen Anbieter für unseren Service erstellt.

Genau das Gleiche können Sie aber auch mit Services tun. Ein Service ist jedoch eine Konstruktorfunktion, die uns nicht daran hindert, Objektliterale zurückzugeben. So können wir unseren Servicecode so schreiben, dass er im Grunde genau das Gleiche wie unsere Fabrik tut, oder mit anderen Worten, Sie können einen Service als Fabrik schreiben, um ein Objekt zurückzugeben.

Warum empfehlen die meisten Menschen, Fabriken anstelle von Dienstleistungen zu nutzen? Dies ist die beste Antwort, die ich gesehen habe und die aus Pawel Kozlowskis Buch stammt: Beherrschen der Entwicklung von Webanwendungen mit AngularJS.

Die Factory-Methode ist die häufigste Methode, um Objekte in das AngularJS-Abhängigkeitsinjektionssystem zu übertragen. Es ist sehr flexibel und kann eine ausgefeilte Erstellungslogik enthalten. Da Fabriken reguläre Funktionen sind, können wir auch einen neuen lexikalischen Bereich nutzen, um "private" Variablen zu simulieren. Dies ist sehr nützlich, da wir Implementierungsdetails eines bestimmten Dienstes verbergen können. "


1
  • Mit der Fabrik erstellen Sie tatsächlich ein Objekt innerhalb der Fabrik und geben es zurück.
  • Mit dem Dienst haben Sie nur eine Standardfunktion , die das thisSchlüsselwort verwendet, um die Funktion zu definieren.
  • Mit dem Anbieter gibt es eine von $getIhnen definiert und es kann verwendet werden , erhalten Sie das Objekt, das die Daten zurückgibt.

1

Es gibt drei Möglichkeiten, mit Geschäftslogik in AngularJS umzugehen: ( Inspiriert von Yaakovs Coursera AngularJS-Kurs ):

  1. Bedienung
  2. Fabrik
  3. Anbieter

Hier werden wir nur über Service vs Factory sprechen

SERVICE :

Syntax:

app.js.

 var app = angular.module('ServiceExample',[]);
 var serviceExampleController =
              app.controller('ServiceExampleController', ServiceExampleController);
 var serviceExample = app.service('NameOfTheService', NameOfTheService);

 ServiceExampleController.$inject = ['NameOfTheService'] //very important as this protects from minification of js files

function ServiceExampleController(NameOfTheService){
     serviceExampleController = this;
     serviceExampleController.data = NameOfTheService.getSomeData();
 }

function NameOfTheService(){
     nameOfTheService = this;
     nameOfTheService.data = "Some Data";
     nameOfTheService.getSomeData = function(){
           return nameOfTheService.data;
     }     
}

index.html

<div ng-controller = "ServiceExampleController as serviceExample">
   {{serviceExample.data}}
</div>

Die Hauptmerkmale von Service:

  1. Lazily Instantiated : Wenn der Dienst nicht injiziert wird, wird er niemals instanziiert. Um es zu verwenden, müssen Sie es in ein Modul injizieren.

  2. Singleton : Wenn es in mehrere Module injiziert wird, haben alle nur Zugriff auf eine bestimmte Instanz. Aus diesem Grund ist es sehr praktisch, Daten zwischen verschiedenen Controllern auszutauschen.

FABRIK

Lassen Sie uns nun über die Fabrik in AngularJS sprechen

Schauen wir uns zunächst die Syntax an :

app.js :

var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);

//first implementation where it returns a function
function NameOfTheFactoryOne(){
   var factory = function(){
      return new SomeService();
    }
   return factory;
}

//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
   var factory = {
      getSomeService : function(){
          return new SomeService();
       }
    };
   return factory;
}

Verwenden Sie nun die beiden oben genannten Elemente in der Steuerung:

 var factoryOne = NameOfTheFactoryOne() //since it returns a function
 factoryOne.someMethod();

 var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
 factoryTwo.someMethod();

Merkmale der Fabrik:

  1. Diese Art von Dienstleistungen folgt dem Konstruktionsmuster der Fabrik . Die Fabrik kann als zentraler Ort betrachtet werden, an dem neue Objekte oder Methoden entstehen.

  2. Dies erzeugt nicht nur Singleton, sondern auch anpassbare Dienste.

  3. Die .service()Methode ist eine Factory , die immer dieselbe Art von Service erzeugt, nämlich einen Singleton. Es gibt keine einfache Möglichkeit, das Verhalten zu konfigurieren. Diese .service()Methode wird normalerweise als Verknüpfung für etwas verwendet, für das keinerlei Konfiguration erforderlich ist.



0

Sie können den Unterschied mit dieser Analogie verstehen - Betrachten Sie den Unterschied zwischen einer normalen Funktion, die einen Wert zurückgibt, und einer Konstruktorfunktion, die mit einem neuen Schlüsselwort instanziiert wird. Das Erstellen einer Factory ähnelt also dem Erstellen einer normalen Funktion, die einen bestimmten Wert zurückgibt (primitiv oder ein Objekt), während das Erstellen eines Dienstes dem Erstellen einer Konstruktorfunktion (OO-Klasse) gleicht, deren Instanz wir mit einem neuen Schlüsselwort erstellen können. Das einzige, was hier zu beachten ist, ist, dass wenn wir die Service-Methode zum Erstellen von Services verwenden, diese automatisch eine Instanz davon mithilfe des von AngularJS unterstützten Abhängigkeitsinjektionsmechanismus erstellt

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.