631 Stimmen

Verwirrt über Service vs. Fabrik

So wie ich es verstehe, gebe ich innerhalb einer Fabrik ein Objekt zurück, das in einen Controller injiziert wird. Wenn ich mich in einem Dienst befinde, behandle ich das Objekt mit this und nichts zurückgeben.

Ich bin davon ausgegangen, dass ein Dienst immer ein Singleton und dass ein neues Fabrikobjekt wird in jeden Controller injiziert. Doch wie sich herausstellt, ist ein Fabrikobjekt 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.first en ACtrl es stellt sich heraus, dass user.first en BCtrl wird ebenfalls geändert, z. B. User ein Singleton ist?

Meine Annahme war, dass eine neue Instanz in einem Controller mit einer Fabrik injiziert wurde?

8voto

Premraj Punkte 65511

Dienst Stil: ( wahrscheinlich die einfachste Variante ) gibt die eigentliche Funktion zurück: Nützlich für die gemeinsame Nutzung von Hilfsfunktionen, die durch einfaches Anhängen von () an die injizierte Funktionsreferenz aufgerufen werden können.

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();

});

Fabrik Stil: ( aufwendiger, aber anspruchsvoller ) gibt den Rückgabewert der Funktion zurück: ein Objekt instanziieren wie new Object() in java.

Factory ist eine Funktion, die Werte erzeugt. Wenn ein Dienst, ein Controller usw. einen Wert benötigt, der von einer Factory injiziert wird, erstellt die Factory den Wert bei Bedarf. Sobald der Wert erstellt ist, wird er für alle Dienste, Controller usw., die ihn benötigen, wiederverwendet.

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);

});

Anbieter Stil: ( vollwertige, konfigurierbare Version ) gibt die Ausgabe der $get-Funktion der Funktion zurück: Konfigurierbar.

Providers in AngularJS sind die flexibelste Form der Factory, die Sie erstellen können. Sie registrieren einen Provider mit einem Modul, genau wie Sie es mit einem Service oder einer Factory tun, nur 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>

へそ曲がり

2voto

Hisham Punkte 2426

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

Dienst : Rückgabe eines Typs, der neu erstellt wird, um ein Objekt dieses Typs zu erzeugen. Wenn die Java-Analogie verwendet wird, gibt Service ein Java-Klassendefinition .

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

Der Teil, der die Leute oft verwirrt (mich eingeschlossen), ist, dass, wenn Sie einen Service oder eine Factory in Ihren Code einbinden, sie auf die gleiche Weise verwendet werden können, was Sie in Ihrem Code in beiden Fällen erhalten, ist ein konkretes Objekt, das Sie sofort aufrufen können. Das heißt, im Falle des Service ruft Angular "new" auf die Service-Deklaration in Ihrem Namen auf. Ich denke, das ist ein verworrenes Konzept.

1voto

Syed Ekram Uddin Punkte 2647

Dies ist die beste und kürzeste Antwort zum Verständnis von Service Vs Factory Vs Provider

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

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

"Es gibt Kommentare im Code, die die Hauptunterschiede veranschaulichen, aber ich werde sie hier ein wenig erläutern. Ich bin gerade dabei, mich in die Materie einzuarbeiten. Wenn ich also etwas Falsches sage, lassen Sie es mich bitte wissen.

Dienstleistungen

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

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

Verwendung : Könnte für die gemeinsame Nutzung von Utility-Funktionen nützlich sein, die durch einfaches Anhängen von () an den Verweis auf die injizierte Funktion aufgerufen werden können. Kann auch mit injectedArg.call( this ) oder ähnlichem ausgeführt werden.

Fabriken

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

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

Verwendung : Könnte nützlich sein, um eine "Klassen"-Funktion zurückzugeben, die dann neu erstellt werden kann, um Instanzen zu erzeugen.

Anbieter

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

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

Verwendung : Könnte nützlich sein, um eine "Klassen"-Funktion zurückzugeben, die dann neu erstellt werden kann, um Instanzen zu erzeugen, die aber eine Art von Konfiguration erfordert, bevor sie injiziert wird. Vielleicht nützlich für Klassen, die projektübergreifend wiederverwendbar sind? Bin mir da noch nicht ganz sicher." Ben

1voto

Safeer Hussain Punkte 1194

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

angular .factory y angular .service werden beide zur Initialisierung eines Dienstes verwendet und funktionieren auf dieselbe Weise.

Der einzige Unterschied ist, wie Sie Ihren Dienst initialisieren wollen.

Beide sind Singletons


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

Fabrik

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

Wenn Sie Ihren Dienst von eine Funktion, die Sie mit einem Rückgabewert haben müssen Sie dies verwenden factory Methode.

z.B..

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

app.factory('myService', myService);

Bei der Einspeisung dieses Dienstes (z. B. in Ihren Controller):

  • Angular wird aufrufen Ihre gegebene Funktion (als myService() ), um das Objekt zurückzugeben
  • Singleton - nur einmal aufgerufen und gespeichert werden und das gleiche Objekt übergeben.

Dienst

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

Wenn Sie Ihren Dienst von eine Konstruktionsfunktion (mit this Schlüsselwort), müssen Sie folgendes verwenden service Methode.

z.B..

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

app.service('myService', myService);

Bei der Einspeisung dieses Dienstes (z. B. in Ihren Controller):

  • Angular wird new Ihrer gegebenen Funktion (als new myService() ), um das Objekt zurückzugeben
  • Singleton - nur einmal aufgerufen und gespeichert werden und das gleiche Objekt übergeben.

HINWEIS: Wenn Sie factory mit <constructor function> ou service mit <function with a return value> wird es nicht funktionieren.


Beispiele - DEMOs

1voto

James Drinkard Punkte 14572

Das hat mir geholfen, den Unterschied zu verstehen, dank eines Blogbeitrags von Pascal Precht.

Ein Dienst ist eine Methode eines Moduls, die einen Namen und eine Funktion annimmt, die den Dienst definiert. Sie können diesen bestimmten Dienst in andere Komponenten wie Controller, Direktiven und Filter injizieren und verwenden. Eine Fabrik ist eine Methode eines Moduls, die ebenfalls einen Namen und eine Funktion benötigt, die die Fabrik definiert. Auch sie kann auf die gleiche Weise wie der Dienst injiziert und verwendet werden.

Objekte, die mit new erstellt werden, verwenden den Wert der prototype-Eigenschaft ihrer Konstruktorfunktion als ihren Prototyp, also habe ich den Angular-Code gefunden, der Object.create() aufruft, was meiner Meinung nach die Konstruktorfunktion des Dienstes ist, wenn er instanziiert wird. Allerdings ist eine Factory-Funktion wirklich nur eine Funktion, die aufgerufen wird, weshalb wir ein Objektliteral für die Factory zurückgeben müssen.

Hier ist der Angular 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;
    }

Angular-Quellcode-Schnipsel 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 übergebene Fabrikfunktion und gibt einen Anbieter mit dem gleichen Namen zurück, der eine $get-Methode hat, die unsere Fabrikfunktion ist. Immer wenn Sie den Injektor nach einer bestimmten Abhängigkeit fragen, fragt er den entsprechenden Anbieter nach einer Instanz dieses Dienstes, indem er die $get()-Methode aufruft. Aus diesem Grund ist $get() bei der Erstellung von Providern erforderlich.

Hier ist der Angular 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 beim Aufruf von service() tatsächlich factory() aufgerufen wird! Es wird jedoch nicht nur die Konstruktorfunktion unseres Dienstes an die Fabrik übergeben, wie sie ist. Es wird auch eine Funktion übergeben, die den Injektor auffordert, ein Objekt mit dem angegebenen Konstruktor zu instanziieren.

Mit anderen Worten, wenn wir MyService irgendwo einfügen, passiert im Code folgendes:

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

Um es noch einmal zu wiederholen: Ein Dienst ruft eine Fabrik auf, die eine $get()-Methode des entsprechenden Anbieters ist. Außerdem ist $injector.instantiate() die Methode, die letztendlich Object.create() mit der Konstruktorfunktion aufruft. Aus diesem Grund verwenden wir "this" in Diensten.

Für ES5 spielt es keine Rolle, was wir verwenden: service() oder factory(), es wird immer eine Factory aufgerufen, die einen Provider für unseren Dienst erstellt.

Genau das Gleiche kann man aber auch mit Dienstleistungen machen. Ein Dienst ist eine Konstruktorfunktion, aber das hindert uns nicht daran, Objektliterale zurückzugeben. Wir können also unseren Dienstcode so schreiben, dass er im Grunde genau das Gleiche tut wie unsere Fabrik, oder anders gesagt, wir können einen Dienst als Fabrik schreiben, um ein Objekt zurückzugeben.

Warum empfehlen die meisten Menschen den Einsatz von Fabriken gegenüber Dienstleistungen? Dies ist die beste Antwort, die ich gesehen habe. Sie stammt aus dem Buch von Pawel Kozlowski: Mastering Web Application Development with AngularJS.

Die Fabrikmethode ist die gebräuchlichste Methode, um AngularJS-Abhängigkeitsinjektionssystem. Sie ist sehr flexibel und kann ausgefeilte Erstellungslogik enthalten. Da Fabriken reguläre Funktionen sind, können wir auch die Vorteile eines neuen lexikalischen Bereichs nutzen, um um "private" Variablen zu simulieren. Dies ist sehr nützlich, da wir die Implementierungsdetails eines bestimmten Dienstes verbergen können."

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X