AngularJS: Wann wird der Service anstelle des Werks verwendet?


296

Bitte ertrage es hier mit mir. Ich weiß, dass es andere Antworten gibt, wie zum Beispiel: AngularJS: Service gegen Anbieter gegen Fabrik

Ich kann jedoch immer noch nicht herausfinden, wann Sie den Service über die Fabrik nutzen würden.

Soweit ich weiß, wird Factory häufig verwendet, um "allgemeine" Funktionen zu erstellen, die von mehreren Controllern aufgerufen werden können: Erstellen gemeinsamer Controller-Funktionen

Die Angular-Dokumente scheinen die Fabrik dem Service vorzuziehen. Sie beziehen sich sogar auf "Service", wenn sie die Fabrik benutzen, was noch verwirrender ist! http://docs.angularjs.org/guide/dev_guide.services.creating_services

Wann würde man den Service nutzen?

Gibt es etwas, das nur mit Service möglich oder viel einfacher ist?

Gibt es etwas anderes, das sich hinter den Kulissen abspielt? Leistungs- / Speicherunterschiede?

Hier ist ein Beispiel. Abgesehen von der Deklarationsmethode scheinen sie identisch zu sein, und ich kann nicht herausfinden, warum ich eins gegen das andere mache. http://jsfiddle.net/uEpkE/

Update: Aus Thomas 'Antwort geht hervor, dass der Service für eine einfachere Logik und die Factory für eine komplexere Logik mit privaten Methoden gedacht ist. Deshalb habe ich den folgenden Geigencode aktualisiert und es scheint, dass beide private Funktionen unterstützen können.

myApp.factory('fooFactory', function() {
    var fooVar;
    var addHi = function(foo){ fooVar = 'Hi '+foo; }

    return {
        setFoobar: function(foo){
            addHi(foo);
        },
        getFoobar:function(){
            return fooVar;
        }
    };
});
myApp.service('fooService', function() {
    var fooVar;
    var addHi = function(foo){ fooVar = 'Hi '+foo;}

    this.setFoobar = function(foo){
        addHi(foo);
    }
    this.getFoobar = function(){
        return fooVar;
    }
});

function MyCtrl($scope, fooService, fooFactory) {
    fooFactory.setFoobar("fooFactory");
    fooService.setFoobar("fooService");
    //foobars = "Hi fooFactory, Hi fooService"
    $scope.foobars = [
        fooFactory.getFoobar(),
        fooService.getFoobar()
    ];
}

Natürlich unterstützt der Service private, aber wenn Sie meinen Beitrag richtig lesen, handelt es sich um einen reinen Codestil: Wir können auch einen neuen lexikalischen Bereich nutzen, um "private" Variablen zu simulieren. Es ist "SIMULATE"
Thomas Pons

Ich finde diese Diskussion sehr nützlich stackoverflow.com/questions/15666048/…
Anand Gupta

Antworten:


280

Erläuterung

Sie haben hier verschiedene Dinge:

Zuerst:

  • Wenn Sie einen Dienst verwenden, erhalten Sie die Instanz einer Funktion ( thisSchlüsselwort " ").
  • Wenn Sie eine Factory verwenden, erhalten Sie den zurückgegebenen Wert durch Aufrufen der Funktionsreferenz (der return-Anweisung in der Factory).

ref: angle.service vs angle.factory

Zweite:

Denken Sie daran, dass alle Anbieter in AngularJS (Wert, Konstante, Dienstleistungen, Fabriken) Singletons sind!

Dritte:

Bei der Verwendung des einen oder anderen (Service oder Fabrik) geht es um den Codestil. Aber der gemeinsame Weg ist in AngularJS verwenden Fabrik .

Warum ?

Denn "Die Factory-Methode ist die häufigste Methode, um Objekte in das AngularJS-Abhängigkeitsinjektionssystem zu bringen. Sie 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" privat "zu simulieren "Variablen. Dies ist sehr nützlich, da wir Implementierungsdetails eines bestimmten Dienstes ausblenden können."

( Ref : http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821 ).


Verwendung

Service: Kann nützlich sein, um Dienstprogrammfunktionen freizugeben, die durch einfaches Anhängen ()an die Referenz der injizierten Funktion aufgerufen werden können. Könnte auch mit injectedArg.call(this)oder ähnlich ausgeführt werden.

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

So verwenden Sie eine Fabrik , wenn Sie komplexe Logik in Ihrem Service und Sie nicht wollen , um diese Komplexität aussetzen .

In anderen Fällen, wenn Sie eine Instanz eines Dienstes zurückgeben möchten, verwenden Sie einfach den Dienst .

Aber Sie werden mit der Zeit sehen, dass Sie in 80% der Fälle, glaube ich, die Fabrik verwenden werden.

Für weitere Informationen: http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/


UPDATE:

Ausgezeichneter Beitrag hier: http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html

"Wenn Sie möchten, dass Ihre Funktion wie eine normale Funktion aufgerufen wird , verwenden Sie Factory . Wenn Sie möchten, dass Ihre Funktion mit dem neuen Operator instanziiert wird, verwenden Sie den Dienst. Wenn Sie den Unterschied nicht kennen, verwenden Sie Factory."


UPDATE:

Das AngularJS-Team macht seine Arbeit und gibt eine Erklärung: http://docs.angularjs.org/guide/providers

Und von dieser Seite:

"Factory und Service sind die am häufigsten verwendeten Rezepte. Der einzige Unterschied besteht darin, dass das Service-Rezept für Objekte benutzerdefinierten Typs besser funktioniert, während Factory JavaScript-Grundelemente und -Funktionen erstellen kann."


7
Zu erstens: Ich habe das überall gelesen, aber ich verstehe die praktischen Auswirkungen nicht. Ich denke aus Ihrer Antwort gibt es keinen praktischen Unterschied "zum größten Teil"? Vielen Dank für die Buchreferenz!
user1941747

Es ist einfach, wenn Ihr Service wirklich komplex ist und Sie private Methoden und Objekte benötigen, die eine Fabrik verwenden
Thomas Pons

1
Ich habe festgestellt, dass Sie hinzugefügt haben: "Wenn Sie eine Instanz eines Dienstes zurückgeben möchten, verwenden Sie einfach den Dienst." Meine Folgefrage wäre, WANN möchten Sie eine Instanz eines Dienstes zurückgeben? Ich versuche hier einen bestimmten Anwendungsfall zu finden.
user1941747

12
"Da Fabriken reguläre Funktionen sind, können wir auch einen neuen lexikalischen Bereich nutzen, um" private "Variablen zu simulieren." - Dies ist nicht spezifisch für Fabriken, Sie können das gleiche mit Dienstleistungen tun ..
Pootzko

Das Google-Team scheint den Service der Fabrik vorzuziehen, was die Dinge noch verwirrender macht! google-styleguide.googlecode.com/svn/trunk/…
xzhang

111

allernhwkim hat ursprünglich eine Antwort auf diese Frage gepostet , die auf seinen Blog verweist. Ein Moderator hat sie jedoch gelöscht. Es ist der einzige Beitrag, den ich gefunden habe, der Ihnen nicht nur sagt, wie Sie dasselbe mit Service, Provider und Factory machen, sondern auch, was Sie mit einem Provider machen können, den Sie mit einer Factory nicht können, und mit Eine Fabrik, die man mit einem Service nicht erreichen kann.

Direkt aus seinem Blog:

app.service('CarService', function() {
   this.dealer="Bad";
    this.numCylinder = 4;
});

app.factory('CarFactory', function() {
    return function(numCylinder) {
      this.dealer="Bad";
        this.numCylinder = numCylinder
    };
});

app.provider('CarProvider', function() {
    this.dealerName = 'Bad';
    this.$get = function() {
        return function(numCylinder) {
            this.numCylinder = numCylinder;
            this.dealer = this.dealerName;
        }
    };
    this.setDealerName = function(str) {
      this.dealerName = str;
    }      
});

Dies zeigt, wie der CarService immer ein Auto mit 4 Zylindern produziert, Sie können es nicht für einzelne Autos ändern. Während CarFactory eine Funktion zurückgibt, die Sie new CarFactoryin Ihrem Controller ausführen können, geben Sie eine Reihe von Zylindern ein, die für dieses Auto spezifisch sind. Das kannst du nicht machennew CarService da CarService ein Objekt und keine Funktion ist.

Die Gründe, warum Fabriken nicht so funktionieren:

app.factory('CarFactory', function(numCylinder) {
      this.dealer="Bad";
      this.numCylinder = numCylinder
});

Und automatisch eine Funktion zurückgeben, die Sie instanziieren können, weil Sie dies dann nicht tun können (fügen Sie dem Prototyp / etc Dinge hinzu):

app.factory('CarFactory', function() {
    function Car(numCylinder) {
        this.dealer="Bad";
        this.numCylinder = numCylinder
    };
    Car.prototype.breakCylinder = function() {
        this.numCylinder -= 1;
    };
    return Car;
});

Sehen Sie, wie es buchstäblich eine Fabrik ist, die ein Auto produziert.

Das Fazit aus seinem Blog ist ziemlich gut:

Abschließend,

---------------------------------------------------  
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------  
| Factory | Yes      | Yes          | No          |
---------------------------------------------------  
| Service | Yes      | No           | No          |
---------------------------------------------------  
| Provider| Yes      | Yes          | Yes         |       
---------------------------------------------------  
  1. Verwenden Sie Service, wenn Sie nur ein einfaches Objekt wie einen Hash benötigen, z. B. {foo; 1, bar: 2}. Es ist einfach zu codieren, aber Sie können es nicht instanziieren.

  2. Verwenden Sie Factory, wenn Sie ein Objekt instanziieren müssen, z. B. neuer Kunde (), neuer Kommentar () usw.

  3. Verwenden Sie Provider, wenn Sie ihn konfigurieren müssen. dh Test-URL, QA-URL, Produktions-URL.

Wenn Sie feststellen, dass Sie nur ein Objekt in der Fabrik zurückgeben, sollten Sie wahrscheinlich den Dienst verwenden.

Tu das nicht:

app.factory('CarFactory', function() {
    return {
        numCylinder: 4
    };
});

Verwenden Sie stattdessen den Service:

app.service('CarService', function() {
    this.numCylinder = 4;
});

11
es ist sehr hilfreich für mich. +1 für Vergleichstabelle
Vu Anh

5
Wenn Sie die Servicefunktion mit einem Parameter numCylinder definieren, hat sie die gleiche Flexibilität wie die Factory-Methode
Ovi

Gehen Sie und lesen Sie den Post-Blog und verschwenden Sie Ihre Zeit damit, Winkel herauszufinden. Wenn Sie nach dem Lesen dieses Posts Javascript kennen, werden Sie den Unterschied zwischen diesen vollständig verstehen.
Ncubica

4
Sehr überrascht ! Sie verweisen hier auf einen Blog und beide sagen das Gegenteil. Sie sagen: Factory - Instantiable - Ja Blog sagen: Factory - Instantiable - Nein
Devesh M

1
Ich stimme @Devesh zu. Ich denke, Sie haben die Instantiate durcheinander gebracht. Aus dem Blog-Beitrag: "Nur mit Factory können Sie dies nicht erreichen, da Factory nicht instanziiert werden kann."
Matt

20

Das Konzept für all diese Anbieter ist viel einfacher als es zunächst erscheint. Wenn Sie einen Anbieter sezieren und die verschiedenen Teile herausziehen, wird dies sehr deutlich.

Um es einfach auszudrücken jede dieser Anbieter ist eine spezielle Version des anderen, in dieser Reihenfolge: provider> factory> value/ constant/ service.

Solange der Anbieter tut, was Sie können, können Sie den Anbieter weiter unten in der Kette verwenden, was dazu führen würde, dass weniger Code geschrieben wird. Wenn es nicht das erreicht, was Sie wollen, können Sie die Kette hochgehen und müssen nur mehr Code schreiben.

Dieses Bild zeigt, was ich meine. In diesem Bild sehen Sie den Code für einen Anbieter. Die hervorgehobenen Teile zeigen Ihnen, welche Teile des Anbieters stattdessen zum Erstellen einer Fabrik, eines Werts usw. verwendet werden könnten.

AngularJS-Anbieter, Fabriken, Dienstleistungen usw. sind alle dasselbe
(Quelle: simplygoodcode.com )

Weitere Details und Beispiele aus dem Blog-Beitrag, von dem ich das Bild erhalten habe, finden Sie unter: http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


8

Sowohl die Factory als auch der Service führen zu Singleton-Objekten, die von Anbietern konfiguriert und in Controller und Ausführungsblöcke eingefügt werden können. Aus Sicht des Injektors gibt es absolut keinen Unterschied, ob das Objekt aus einer Fabrik oder einer Dienstleistung stammt.

Wann sollte eine Fabrik und wann ein Service genutzt werden? Es läuft auf Ihre Codierungspräferenz hinaus und auf nichts anderes. Wenn Sie das modulare JS-Muster mögen, gehen Sie zur Fabrik. Wenn Ihnen der Stil der Konstruktorfunktion ("Klasse") gefällt, wählen Sie den Dienst. Beachten Sie, dass beide Stile private Mitglieder unterstützen.

Der Vorteil des Dienstes könnte darin bestehen, dass er aus OOP-Sicht intuitiver ist: Erstellen Sie eine "Klasse" und verwenden Sie in Verbindung mit einem Anbieter denselben Code modulübergreifend wieder, und variieren Sie das Verhalten der instanziierten Objekte einfach durch Angabe verschiedene Parameter zum Konstruktor in einem Konfigurationsblock.


Können Sie ein Beispiel dafür geben, was Sie unter verschiedenen Parametern für den Konstruktor in einem Konfigurationsblock verstehen? Wie stellen Sie Parameter bereit, wenn es sich nur um einen Service oder eine Fabrik handelt? Was meinst du mit "in Verbindung mit einem Anbieter"? Wenn ich es konfigurieren kann, denke ich, dass viele meiner Objekte Anbieter oder Fabriken oder Dienstleistungen sein sollten.
Timbrown

2

Es gibt nichts, was eine Fabrik im Vergleich zu einem Service nicht kann oder besser kann. Und umgekehrt. Fabrik scheint nur populärer zu sein. Der Grund dafür ist die Bequemlichkeit im Umgang mit privaten / öffentlichen Mitgliedern. Der Service wäre in dieser Hinsicht ungeschickter. Wenn Sie einen Dienst codieren, neigen Sie dazu, Ihre Objektmitglieder über das Schlüsselwort "this" öffentlich zu machen, und stellen möglicherweise plötzlich fest, dass diese öffentlichen Mitglieder für private Methoden (dh innere Funktionen) nicht sichtbar sind.

var Service = function(){

  //public
  this.age = 13;

  //private
  function getAge(){

    return this.age; //private does not see public

  }

  console.log("age: " + getAge());

};

var s = new Service(); //prints 'age: undefined'

Angular verwendet das Schlüsselwort "new", um einen Dienst für Sie zu erstellen, sodass die Instanz, die Angular an den Controller übergibt, denselben Nachteil hat. Natürlich können Sie das Problem überwinden, indem Sie Folgendes verwenden:

var Service = function(){

  var that = this;

  //public
  this.age = 13;

  //private
  function getAge(){

    return that.age;

  }

  console.log("age: " + getAge());

};

var s = new Service();// prints 'age: 13'  

Aber mit einer großen Service-Konstante würde dies den Code schlecht lesbar machen. Darüber hinaus werden die Service-Prototypen keine privaten Mitglieder sehen - nur öffentliche werden ihnen zur Verfügung stehen:

var Service = function(){

  var name = "George";

};

Service.prototype.getName = function(){

  return this.name; //will not see a private member

};

var s = new Service();
console.log("name: " + s.getName());//prints 'name: undefined'

Zusammenfassend ist die Verwendung von Factory bequemer. As Factory hat diese Nachteile nicht. Ich würde empfehlen, es standardmäßig zu verwenden.


Diese Antwort hat mehrere Probleme. Zunächst wird in diesem Beitrag das Konzept des lexikalischen Scoping von Javascript demonstriert und nicht die Funktionsweise von AngularJS-Diensten. Zweitens myapp.service(...)fehlt der Kontext des Aufrufs vollständig. Wo new Service()soll aufgerufen werden, in der Servicefunktion oder an der Stelle, an der der Service injiziert wird. Die dritte Auflistung ist im Kontext von einfach nicht möglich myapp.service ('Service', function() {...}).
Lanoxx

2

Selbst wenn sie sagen, dass alle Dienstleistungen und Fabriken Singleton sind, stimme ich dem nicht zu 100 Prozent zu. Ich würde sagen, dass Fabriken keine Singletons sind und das ist der Punkt meiner Antwort. Ich würde wirklich über den Namen nachdenken, der jede Komponente definiert (Service / Fabrik), ich meine:

Eine Fabrik , da ist kein Singleton, können Sie so viele erstellen , wie Sie wollen , wenn Sie injizieren, so dass es wie eine Fabrik von Objekten arbeitet. Sie können eine Factory einer Entität Ihrer Domäne erstellen und bequemer mit diesen Objekten arbeiten, die wie ein Objekt Ihres Modells sein können. Wenn Sie mehrere Objekte abrufen, können Sie sie in diesen Objekten zuordnen und es kann eine Art andere Ebene zwischen dem DDBB- und dem AngularJs-Modell fungieren. Sie können den Objekten Methoden hinzufügen, sodass Sie sich ein wenig mehr an Objekten orientieren als an Ihrer AngularJs-App.

In der Zwischenzeit ist ein Dienst ein Singleton, sodass wir nur eine Instanz erstellen können, möglicherweise nicht, aber wir haben nur eine Instanz, wenn wir einen Controller einfügen. Daher bietet ein Dienst eher einen allgemeinen Dienst (Restaufrufe, Funktionalität ..). zu den Controllern.

Konzeptionell kann man denken, dass Services einen Service bereitstellen. Fabriken können mehrere Instanzen (Objekte) einer Klasse erstellen


0

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.


0

Kann beides so verwenden, wie Sie möchten : ob Sie ein Objekt erstellen oder nur , um von beiden auf Funktionen zuzugreifen


Sie können ein neues Objekt aus dem Dienst erstellen

app.service('carservice', function() {
    this.model = function(){
        this.name = Math.random(22222);
        this.price = 1000;
        this.colour = 'green';
        this.manufacturer = 'bmw';
    }
});

.controller('carcontroller', function ($scope,carservice) { 
    $scope = new carservice.model();
})

Hinweis :

  • Der Dienst gibt standardmäßig das Objekt und nicht die Konstruktorfunktion zurück.
  • Aus diesem Grund wird die Konstruktorfunktion auf die Eigenschaft this.model gesetzt.
  • Aufgrund dieses Dienstes wird das Objekt zurückgegeben, aber innerhalb dieses Objekts befindet sich eine Konstruktorfunktion, die zum Erstellen eines neuen Objekts verwendet wird.

Sie können ab Werk ein neues Objekt erstellen

app.factory('carfactory', function() {
    var model = function(){
        this.name = Math.random(22222);
        this.price = 1000;
        this.colour = 'green';
        this.manufacturer = 'bmw';
    }
    return model;
});

.controller('carcontroller', function ($scope,carfactory) { 
    $scope = new carfactory();
})

Hinweis :

  • factory gibt standardmäßig die Konstruktorfunktion und nicht das Objekt zurück.
  • Deshalb kann mit der Konstruktorfunktion ein neues Objekt erstellt werden.

Erstellen Sie einen Dienst für den einfachen Zugriff auf einfache Funktionen

app.service('carservice', function () {
   this.createCar = function () {
       console.log('createCar');
   };
   this.deleteCar = function () {
       console.log('deleteCar');
   };
});

.controller('MyService', function ($scope,carservice) { 
    carservice.createCar()
})

Erstellen Sie eine Factory, um nur auf einfache Funktionen zuzugreifen

app.factory('carfactory', function () {
    var obj = {} 
        obj.createCar = function () {
            console.log('createCar');
        };
       obj.deleteCar = function () {
       console.log('deleteCar');
    };
});

.controller('MyService', function ($scope,carfactory) { 
    carfactory.createCar()
})

Fazit :

  • Sie können beide verwenden , wie Sie wollen , ob neues Objekt erstellen oder einfach nur den Zugriff auf einfache Funktionen
  • Es wird keinen Leistungseinbruch geben, wenn einer über den anderen verwendet wird
  • Beide sind Singleton-Objekte und pro App wird nur eine Instanz erstellt.
  • Dies ist nur eine Instanz, an der ihre Referenz übergeben wird.
  • In der Winkeldokumentation wird die Fabrik als Service und auch der Service als Service bezeichnet .

0

Fabrik und Service sind die am häufigsten verwendete Methode. Der einzige Unterschied besteht darin, dass die Service-Methode für Objekte, die eine Vererbungshierarchie benötigen, besser funktioniert, während die Factory JavaScript-Grundelemente und -Funktionen erstellen kann.

Die Provider-Funktion ist die Kernmethode und alle anderen sind nur syntaktischer Zucker. Sie benötigen es nur, wenn Sie einen wiederverwendbaren Code erstellen, der global konfiguriert werden muss.

Es gibt fünf Methoden zum Erstellen von Diensten: Wert, Fabrik, Dienst, Anbieter und Konstante. Sie können mehr über diese hier erfahren Winkel Service , dieser Artikel alle diese Methoden mit praktischen Demo - Beispiele erläutern.

.

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.