Confuso su Service vs Factory


618

A quanto ho capito, quando all'interno di una fabbrica restituisco un oggetto che viene iniettato in un controller. All'interno di un servizio ho a che fare con l'oggetto che usa thise non restituisce nulla.

Pensavo che un servizio fosse sempre un singleton e che un nuovo oggetto di fabbrica venisse iniettato in ogni controller. Tuttavia, a quanto pare, anche un oggetto factory è un singleton?

Codice di esempio per dimostrare:

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

Quando si cambia user.firstin ACtrlrisulta che user.firstnel BCtrlcambia anche, ad esempio, Userè un singoletto?

La mia ipotesi era che una nuova istanza fosse iniettata in un controller con una fabbrica?


4
Accanto a "module.service" e "module.factory" ci sono altri 2 modi per creare servizi in AngularJS. Per ulteriori informazioni, consultare il post del blog: " Come creare (singleton) i servizi AngularJS in 4 modi diversi "
Emil van Galen,

Risposte:


600

Tutti i servizi angolari sono singoli :

Documenti (vedi Servizi come singoli ): https://docs.angularjs.org/guide/services

Infine, è importante rendersi conto che tutti i servizi angolari sono applicazioni singole. Ciò significa che esiste solo un'istanza di un determinato servizio per iniettore.

Fondamentalmente la differenza tra il servizio e la fabbrica è la seguente:

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 + "!";
    }
  }
});

Dai un'occhiata a questa presentazione su $ fornire: http://slides.wesalvaro.com/20121113/#/

Queste diapositive sono state utilizzate in uno dei Meetup di AngularJs: http://blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html


13
Vedi anche stackoverflow.com/questions/15666048/… che discute le differenze tra servizio, fabbrica e fornitura.
Mark Rajcok,

31
Il documento ufficiale indirettamente [sic! non abbastanza chiaro] implica che anche se si definisce il servizio con factory, viene creato una sola volta. In altre parole, NON viene creato di nuovo secondo il riferimento (punto di iniezione), come lo chiami. In entrambi i modi si ottiene un'istanza singleton per iniettore.
honzajde,

3
Dici che "il servizio è solo una funzione di costruzione che verrà chiamata con" nuovo "" ma penso che sia fuorviante. Non penso che si chiami con nuovo dietro le quinte, penso che lo sviluppatore sia responsabile di invocarlo new.
Tim Kindberg,

5
@nfiniteloop, controlla il codice sorgente vicino alla linea 3574. Le fabbriche sono il metodo $ get del provider, ei servizi generano fabbriche usando un metodo che chiama $ injector.instantiate sulla funzione fornita, che poi chiama new. ( See Docs )
citizenslave

14
Avevo l'impressione che un servizio fosse singleton che hai usato ottenendone un riferimento. E che una fabbrica era un singleton che ogni volta restituiva un nuovo oggetto. Cioè, un servizio ti darebbe una "macchina" e tutto nel tuo progetto userebbe questa macchina. Mentre una fabbrica ti darebbe una nuova auto ogni volta che invocavi la fabbrica. Uno era un singleton che restituiva un singleton e uno era un singleton che restituiva un oggetto. Qualcuno può spiegare? Chiamare tutto come un singleton non aiuta poiché può riferirsi a più cose.
user2483724

380

Per me la rivelazione è arrivata quando mi sono reso conto che funzionano tutti allo stesso modo: eseguendo qualcosa una volta , memorizzando il valore che ottengono, e poi tossendo lo stesso valore memorizzato quando si fa riferimento tramite Dependency Injection.

Dì che abbiamo:

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

La differenza tra i tre è che:

  1. aIl valore memorizzato proviene dall'esecuzione fn, in altre parole:fn()
  2. bIl valore memorizzato deriva da newing fn, in altre parole:new fn()
  3. cIl valore memorizzato proviene dapprima ottenendo un'istanza tramite newing fn, quindi eseguendo un $getmetodo dell'istanza

il che significa che c'è qualcosa come un oggetto cache all'interno dell'angolo, il cui valore di ogni iniezione viene assegnato una sola volta, quando sono stati iniettati la prima volta e dove:

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

Questo è il motivo per cui usiamo thisnei servizi e definiamo un this.$getin provider.

Spero che sia di aiuto.


54
infine, una spiegazione sana. L'angolare è pazzo e così totalmente cattivo che fa male.
Osiride,

8
Questa dovrebbe essere la risposta accettata in quanto risponde effettivamente alla domanda PERCHÉ fabbriche, servizi e fornitori restituiscono valori singleton. Le altre risposte spiegano la differenza tra fabbriche, servizi e fornitori, ma non toccano mai l'aspetto singleton.
Passeggiata

3
Mi piace questo ... Quando leggo le mille righe di frase di altri blogger .. riesco solo a capire la fabbrica. Ma ho letto questo ... ho capito tutto il 3
tsohtan il

@osiris sono d'accordo. Non mi piace È così spaventosamente accoppiato che mi fa digrignare i denti.
Thomas,

2
quindi è necessario fornire un'implementazione di $ get quando si utilizzano i provider?
Victor,

95

esempio dal vivo

esempio "ciao mondo"

con 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

Esiste anche un modo per restituire una funzione di costruzione in modo da poter restituire classi nuove in fabbriche, come questa:

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

Quindi puoi farlo in un controller, che utilizza MyObjectWithParam:

var obj = new MyObjectWithParam("hello"),

Vedi qui l'esempio completo:
http://plnkr.co/edit/GKnhIN?p=preview

E qui le pagine del gruppo google, dove è stato discusso:
https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ


Sto riscontrando problemi con la minificazione usando il tuo esempio. Sai come dovrei annotare questo?
Pål,

2
Sì, esiste una notazione minimizzata per Angular. Dovrebbe essere qualcosa del genere: App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); leggi di più qui: docs.angularjs.org/tutorial/step_05
JustGoscha,

4
perché vorresti fare questo, se puoi usare .serviceinvece?
flup

ho avuto lo stesso pensiero @flup. @justgoscha, c'è qualche vantaggio ( percepito? ) dell'uso .factoryrispetto a .service?
xandercoded

5
Penso che un servizio sia un singleton . Quello che ho costruito qui è fondamentalmente una classe che è rinnovabile. Quindi puoi avere qualcosa come una fabbrica di servizi automobilistici e quindi creare new Car('BMW')e new Car('Ford')non condividono le stesse variabili e tutto il resto.
JustGoscha,

51

Ecco le differenze principali:

Servizi

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

Risultato: quando si dichiara serviceName come argomento iniettabile, verrà fornita l' istanza di una funzione passata a module.service.

Utilizzo: potrebbe essere utile per la condivisione di funzioni di utilità utili per richiamare semplicemente aggiungendo () al riferimento della funzione iniettata. Potrebbe anche essere eseguito con injectedArg.call( this )o simili.

fabbriche

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

Risultato: quando si dichiara factoryName come argomento iniettabile, verrà fornito il valore restituito invocando il riferimento della funzione passato a module.factory.

Utilizzo: potrebbe essere utile per restituire una funzione 'class' che può quindi essere modificata per creare istanze.

Controlla anche la documentazione di AngularJS e una domanda simile su StackOverflow confuso su servizio vs fabbrica .

Ecco un esempio di utilizzo dei servizi e della fabbrica . Maggiori informazioni sul servizio AngularJS vs factory .


6
Questo ha senso per me. La fabbrica restituisce il progetto per la creazione di nuovi oggetti.

27

Aggiungendo alla prima risposta, penso che .service () sia per le persone che hanno scritto il loro codice in uno stile più orientato agli oggetti (C # / Java) (usando questa parola chiave e creando un'istanza dell'oggetto tramite la funzione prototipo / costruttore).

Factory è per gli sviluppatori che scrivono codice più naturale per lo stile javascript / funzionale della codifica.

Dai un'occhiata al codice sorgente del metodo .service e .factory all'interno di angular.js - internamente chiamano tutti il ​​metodo del provider:

  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

Molto semplicemente:

.service - la funzione registrata verrà invocata come costruttore (alias 'newed')

.factory - la funzione registrata verrà invocata come una semplice funzione

Entrambi vengono richiamati una volta risultando in un oggetto singleton che viene iniettato in altri componenti dell'app.


6
sì. non rendiamo le cose più complicate di quanto non siano in realtà
flup

20

Tutti i provider funzionano allo stesso modo. I diversi metodi service, factory, providersolo consentono di ottenere lo stesso risultato in meno codice.

PS C'è anche valuee constant.

Ogni caso speciale lungo la catena che inizia providere termina con valueha un'ulteriore limitazione. Quindi per decidere tra loro devi chiederti quale ti permette di realizzare ciò che vuoi con meno codice.

Ecco una foto che ti mostra cosa intendo:

inserisci qui la descrizione dell'immagine

Puoi una guida dettagliata e di riferimento sul post del blog Ho ottenuto questa immagine da:

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


Si dice che i servizi siano singleton, ma come mai è singleton, se viene creata una nuova istanza ogni volta che la inserisco?
Ankur Marwaha,

1
@AnkurMarwaha Una nuova istanza non viene creata ogni volta, viene creata una sola volta e memorizzata nella cache da AngularJS. Questo è vero se si utilizza un fornitore, una fabbrica, un servizio, ecc. È possibile confermare ciò utilizzando console.log()e iniettando in più controller.
Luis Perez,

Luis, il tuo commento è in conflitto con la risposta accettata come dice - Infine, è importante rendersi conto che tutti i servizi angolari sono singoli punti di applicazione. Ciò significa che esiste solo un'istanza di un determinato servizio per iniettore.
Ankur Marwaha,

@AnkurMarwaha forse sto fraintendendo qualcosa. Hai citato "è importante rendersi conto che tutti i servizi angolari sono singleton applicativi" - il fatto che siano singleton significa che vengono creati una sola volta. È quello che ho detto "Una nuova istanza non viene creata ogni volta, viene creata una sola volta e memorizzata nella cache ...". Puoi indicare più in dettaglio dove vedi il conflitto?
Luis Perez,

1
Ah, vedo la confusione. L '"iniettore" è un oggetto angolare. È incaricato di fare "l'iniezione". Esempio, quando il controller viene eseguito per la prima volta, l'iniettore esamina i parametri e li inietta. Esiste un solo "iniettore" per l'intera app. Una volta che l'iniettore crea una particolare fabbrica o servizio, conserva un'istanza e la riutilizza - da qui il singleton. Quindi esiste un solo iniettore per app e solo un'istanza di un determinato servizio per iniettore. La maggior parte delle applicazioni angolari ha solo un'app, quindi un iniettore, quindi un'istanza di qualsiasi servizio, controller, ecc.
Luis Perez,

13

Ecco alcuni altri esempi di servizi vs fabbriche che possono essere utili per vedere la differenza tra loro. Fondamentalmente, un servizio ha chiamato "nuovo ...", è già istanziato. Una fabbrica non viene istanziata automaticamente.

Esempi di base

Restituisce un oggetto classe che ha un singolo metodo

Ecco un servizio che ha un solo metodo:

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

Ecco una factory che restituisce un oggetto con un metodo:

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

Restituisce un valore

Una fabbrica che restituisce un elenco di numeri:

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

console.log(NumberListFactory);

Un servizio che restituisce un elenco di numeri:

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

console.log(NumberLister.numbers);

L'output in entrambi i casi è lo stesso, l'elenco dei numeri.

Esempi avanzati

Variabili di "classe" che utilizzano fabbriche

In questo esempio definiamo CounterFactory, incrementa o decrementa un contatore e puoi ottenere il conteggio corrente o ottenere quanti oggetti CounterFactory sono stati creati:

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

})

Usiamo il CounterFactoryper creare più contatori. Possiamo accedere alla variabile di classe per vedere quanti contatori sono stati creati:

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

L'output di questo codice è:

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

è un esempio utile, number_of_counter_factories è come un meta-attributo della classe CounterFactory, giusto ?, capisco che questo esempio è replicabile su un servizio (dimmi se sbaglio), quale sarebbe la differenza semantica in questo caso?
geoom,

Esempio utile! Quindi questo in pratica significa che in una fabbrica è possibile avere quel livello aggiuntivo di astrazione che non sarebbe utile in un servizio. Qualunque cosa venga restituita, tuttavia, verrà restituita una nuova istanza ogni volta che viene utilizzato "nuovo". Qualsiasi variabile non dichiarata all'interno del blocco di ritorno sarà singleton. Ho capito bene?
Swanidhi,

@Swanidhi praticamente sì, puoi dichiarare variabili che sono singleton in fabbrica. Ecco perché le ho chiamate variabili di "classe".

13

"Factory" e "Service" sono modi diversi di eseguire DI (iniezione di dipendenza) in angolare.

Quindi quando definiamo DI usando "service" come mostrato nel codice qui sotto. Questo crea una nuova istanza GLOBALE dell'oggetto “Logger” e lo inietta nella funzione.

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

Quando si definisce DI utilizzando una "factory", non viene creata un'istanza. Passa semplicemente il metodo e in seguito il consumatore deve effettuare internamente chiamate alla fabbrica per le istanze di oggetti.

app.factory("Customerfactory", CreateCustomer);

Di seguito è riportata una semplice immagine che mostra visivamente in che modo il processo DI per "Service" è diverso da "Factory".

inserisci qui la descrizione dell'immagine

Factory dovrebbe essere usato Quando vogliamo creare diversi tipi di oggetti a seconda degli scenari. Ad esempio, a seconda dello scenario, vogliamo creare un semplice oggetto "Cliente" o "Cliente" con oggetto "Indirizzo" o "Cliente" con oggetto "Telefono". Ecco una spiegazione dettagliata di questo paragrafo

Il servizio deve essere utilizzato quando abbiamo funzioni di utilità o condivise da iniettare come Utility, Logger, Handler di errori, ecc.


Ogni risposta che ho visto su questa domanda e altre simili specifica la differenza nella meccanica e nella sintassi. Questa risposta fornisce una vera ragione per cui dovresti selezionare l'uno sull'altro. È una questione di semantica e guardare il nome, il servizio o la fabbrica, comunica il loro scopo e come vengono utilizzati.
Joe Mayo,

8

Stile di servizio : ( probabilmente il più semplice ) restituisce la funzione effettiva: utile per condividere funzioni di utilità utili per richiamare semplicemente aggiungendo () al riferimento della funzione iniettata.

Un servizio in AngularJS è un oggetto JavaScript singleton che contiene un set di funzioni

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

});

Stile di fabbrica : ( più coinvolto ma più sofisticato ) restituisce il valore di ritorno della funzione: creare un'istanza di un oggetto come il nuovo oggetto () in Java.

Factory è una funzione che crea valori. Quando un servizio, un controller ecc. Necessita di un valore iniettato da una fabbrica, la fabbrica crea il valore su richiesta. Una volta creato, il valore viene riutilizzato per tutti i servizi, i controller ecc. Che ne richiedono l'iniezione.

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

});

Stile provider : (versione completa e configurabile ) restituisce l'output della funzione $ get della funzione: configurabile.

I fornitori di AngularJS sono la forma più flessibile di fabbrica che puoi creare. Registri un fornitore con un modulo proprio come fai con un servizio o una fabbrica, tranne che invece usi la funzione provider ().

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

La differenza di base è che il provider consente di impostare i valori di funzione primitiva (non oggetti), array o callback nella variabile dichiarata dalla fabbrica, e quindi se restituisce un oggetto deve essere esplicitamente dichiarato e restituito.

D'altra parte un servizio può essere utilizzato solo per impostare la variabile dichiarata di servizio su un oggetto, quindi possiamo evitare la creazione e la restituzione esplicite degli oggetti, mentre d'altra parte consente l'uso di questa parola chiave.

O in parole povere " provider è una forma più generica mentre il servizio è limitato ai soli oggetti".


2

Ecco come ho compreso la differenza tra loro in termini di modelli di progettazione:

Servizio : restituisce un tipo, che verrà rinnovato per creare un oggetto di quel tipo. Se si utilizza l'analogia Java, Service restituisce una definizione di classe Java .

Factory : restituisce un oggetto concreto che può essere immediatamente utilizzato. Nell'analogia Java una Factory restituisce un oggetto Java .

La parte che spesso confonde le persone (incluso me stesso) è che quando si inietta un Servizio o una Fabbrica nel proprio codice, possono essere utilizzati allo stesso modo, ciò che si ottiene nel codice in entrambi i casi è un oggetto concreto che si può immediatamente invocare. Ciò significa che, nel caso del Servizio, Angular chiama "nuovo" nella dichiarazione di servizio per conto dell'utente. Penso che questo sia un concetto contorto.


1

Questa sarebbe la risposta migliore e breve per comprendere Service Vs Factory Vs Provider

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

Ecco cosa dice Ben con una demo http://jsbin.com/ohamub/1/edit?html, output

"Ci sono commenti nel codice che illustrano le differenze principali, ma mi espanderò un po 'su di esse qui. Come nota, mi sto solo concentrando su questo, quindi se dico qualcosa di sbagliato per favore fatemelo sapere.

Servizi

Sintassi : module.service ('serviceName', funzione);

Risultato : quando si dichiara serviceName come argomento iniettabile, verrà fornito il riferimento effettivo della funzione passato a module.service.

Utilizzo : potrebbe essere utile per la condivisione di funzioni di utilità utili per richiamare semplicemente aggiungendo () al riferimento della funzione iniettata. Potrebbe anche essere eseguito con injectedArg.call (questo) o simile.

fabbriche

Sintassi : module.factory ('factoryName', funzione);

Risultato : quando si dichiara factoryName come argomento iniettabile, verrà fornito il valore restituito invocando il riferimento della funzione passato a module.factory.

Utilizzo : potrebbe essere utile per restituire una funzione 'class' che può quindi essere modificata per creare istanze.

provider

Sintassi : module.provider ('providerName', funzione);

Risultato : quando si dichiara providerName come argomento iniettabile, verrà fornito il valore restituito invocando il metodo $ get del riferimento della funzione passato a module.provider.

Utilizzo : potrebbe essere utile per restituire una funzione 'class' che può quindi essere modificata per creare istanze ma che richiede una sorta di configurazione prima di essere iniettata. Forse utile per le classi che sono riutilizzabili tra i progetti? Ancora un po 'confuso su questo. "Ben


1

Ho avuto questa confusione per un po 'e sto facendo del mio meglio per fornire una semplice spiegazione qui. Spero che questo possa aiutare!

angular .factoryed angular .serviceentrambi vengono utilizzati per inizializzare un servizio e funzionare allo stesso modo.

L'unica differenza è, come si desidera inizializzare il servizio.

Entrambi sono Singletons


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


Fabbrica

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

Se desideri inizializzare il tuo servizio da una funzione che hai con un valore di ritorno , devi usare questo factorymetodo.

per esempio

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

app.factory('myService', myService);

Quando si inietta questo servizio (ad es. Al proprio controller):

  • Angular chiamerà la tua data funzione (as myService()) per restituire l'oggetto
  • Singleton - chiamato solo una volta, memorizzato e passa lo stesso oggetto.


Servizio

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

Se si desidera inizializzare il servizio da una funzione di costruzione (utilizzandothis parola chiave), è necessario utilizzare questo servicemetodo.

per esempio

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

app.service('myService', myService);

Quando si inietta questo servizio (ad es. Al proprio controller):

  • La volontà angolare della newtua data funzione (as new myService()) per restituire l'oggetto
  • Singleton - chiamato solo una volta, memorizzato e passa lo stesso oggetto.


NOTA: se si utilizza factorycon <constructor function>o servicecon <function with a return value>, non funzionerà.


Esempi - DEMO


1

Questo è ciò che mi ha aiutato a capire la differenza, grazie a un post sul blog di Pascal Precht.

Un servizio è un metodo su un modulo che accetta un nome e una funzione che definisce il servizio. È possibile iniettare e utilizzare quel particolare servizio in altri componenti, come controller, direttive e filtri. Una factory è un metodo su un modulo e richiede anche un nome e una funzione, che definisce la factory. Possiamo anche iniettare e utilizzare come abbiamo fatto con il servizio.

Gli oggetti creati con nuovo usano il valore della proprietà prototipo della loro funzione di costruzione come prototipo, quindi ho trovato il codice angolare che chiama Object.create (), che credo sia la funzione di costruzione del servizio quando viene istanziata. Tuttavia, una funzione factory è in realtà solo una funzione che viene chiamata, motivo per cui dobbiamo restituire un oggetto letterale per la factory.

Ecco il codice 1.5 angolare che ho trovato per la fabbrica:

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

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

Frammento di codice sorgente angolare per la funzione factory ():

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

Prende il nome e la funzione factory che viene passata e restituisce un provider con lo stesso nome, che ha un metodo $ get che è la nostra funzione factory. Ogni volta che chiedi all'iniettore una dipendenza specifica, in pratica chiede al provider corrispondente un'istanza di quel servizio, chiamando il metodo $ get (). Ecco perché $ get () è richiesto, durante la creazione di provider.

Ecco il codice angolare 1.5 per l'assistenza.

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

Si scopre che quando chiamiamo service (), in realtà chiama factory ()! Tuttavia, non solo passa la nostra funzione di costruttore di servizi alla fabbrica così com'è. Passa anche una funzione che chiede all'iniettore di creare un'istanza di un oggetto dal costruttore dato.

In altre parole, se iniettiamo MyService da qualche parte, ciò che accade nel codice è:

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

Per riaffermarlo di nuovo, un servizio chiama una factory, che è un metodo $ get () sul provider corrispondente. Inoltre, $ injector.instantiate () è il metodo che alla fine chiama Object.create () con la funzione di costruzione. Ecco perché usiamo "questo" nei servizi.

Per ES5 non importa quale utilizziamo: service () o factory (), è sempre una factory chiamata che crea un provider per il nostro servizio.

Puoi fare esattamente la stessa cosa anche con i servizi. Un servizio è una funzione di costruzione, tuttavia, che non ci impedisce di restituire valori letterali di oggetti. Quindi possiamo prendere il nostro codice di servizio e scriverlo in modo che sostanzialmente faccia la stessa cosa della nostra fabbrica o in altre parole, puoi scrivere un servizio come fabbrica per restituire un oggetto.

Perché la maggior parte delle persone consiglia di utilizzare le fabbriche rispetto ai servizi? Questa è la migliore risposta che ho visto che proviene dal libro di Pawel Kozlowski: padroneggiare lo sviluppo di applicazioni Web con AngularJS.

Il metodo di fabbrica è il modo più comune per ottenere oggetti nel sistema di iniezione di dipendenza AngularJS. È molto flessibile e può contenere una sofisticata logica di creazione. Poiché le fabbriche sono funzioni regolari, possiamo anche trarre vantaggio da un nuovo ambito lessicale per simulare variabili "private". Questo è molto utile in quanto possiamo nascondere i dettagli di implementazione di un determinato servizio. "


1
  • Con la fabbrica si crea effettivamente un oggetto all'interno della fabbrica e lo si restituisce.
  • Con il servizio hai solo una funzione standard che utilizza il this parola chiave per definire la funzione.
  • Con il provider c'è un valore $getdefinito e può essere utilizzato per ottenere l'oggetto che restituisce i dati.

1

Esistono tre modi di gestire la logica aziendale in AngularJS: ( Ispirato al corso Coursera AngularJS di Yaakov ) che sono:

  1. Servizio
  2. Fabbrica
  3. Provider

Qui parleremo solo di Service vs Factory

SERVIZIO :

Sintassi:

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>

Le principali caratteristiche del servizio:

  1. Pigramente istanziato : se il servizio non viene iniettato, non verrà mai istanziato. Quindi per usarlo dovrai iniettarlo in un modulo.

  2. Singleton : se viene iniettato in più moduli, tutti avranno accesso a una sola istanza particolare. Ecco perché, è molto comodo condividere i dati tra diversi controller.

FABBRICA

Ora parliamo della fabbrica di AngularJS

Per prima cosa diamo un'occhiata alla sintassi :

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

Ora usando i due sopra nel controller:

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

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

Caratteristiche di fabbrica:

  1. Questo tipo di servizi segue il modello di progettazione di fabbrica . La fabbrica può essere pensata come un luogo centrale che crea nuovi oggetti o metodi.

  2. Questo non solo produce singleton, ma anche servizi personalizzabili.

  3. Il .service()metodo è una factory che produce sempre lo stesso tipo di servizio, che è un singleton. Non esiste un modo semplice per configurarne il comportamento. Questo .service()metodo viene solitamente utilizzato come scorciatoia per qualcosa che non richiede alcuna configurazione.



0

Puoi capire la differenza con questa analogia: considera la differenza tra una funzione normale che restituirà un valore e una funzione di costruzione che verrà istanziata usando una nuova parola chiave. Quindi creare factory è simile alla creazione di una funzione normale che restituirà un valore (primitivo o un oggetto) mentre creare un servizio è come creare una funzione di costruzione (classe OO) di cui possiamo creare istanza usando una nuova parola chiave. L'unica cosa da notare è che quando usiamo il metodo Service per creare servizi, ne creerà automaticamente un'istanza usando il meccanismo di iniezione di dipendenza supportato da AngularJS

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.