AngularJS: quando utilizzare l'assistenza anziché la fabbrica


296

Per favore, abbi pazienza qui. So che ci sono altre risposte come: AngularJS: Service vs provider vs factory

Tuttavia, non riesco ancora a capire quando useresti il ​​servizio in fabbrica.

Da quello che posso dire factory è comunemente usato per creare funzioni "comuni" che possono essere chiamate da più controller: Creazione di funzioni di controller comuni

I documenti angolari sembrano preferire la fabbrica al servizio. Si riferiscono anche al "servizio" quando usano la fabbrica che è ancora più confusa! http://docs.angularjs.org/guide/dev_guide.services.creating_services

Quindi quando si dovrebbe usare il servizio?

C'è qualcosa che è solo possibile o molto più semplice fatto con il servizio?

C'è qualcosa di diverso che accade dietro le quinte? Differenze prestazioni / memoria?

Ecco un esempio A parte il metodo di dichiarazione, sembrano identici e non riesco a capire perché dovrei fare l'uno contro l'altro. http://jsfiddle.net/uEpkE/

Aggiornamento: Dalla risposta di Thomas sembra implicare che il servizio è per una logica e una fabbrica più semplici per una logica più complessa con metodi privati, quindi ho aggiornato il codice del violino di seguito e sembra che entrambi siano in grado di supportare funzioni private?

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

ovviamente il servizio supporta private ma se leggi correttamente il mio post è puramente in stile codice: possiamo anche sfruttare un nuovo ambito lessicale per simulare variabili "private". È "SIMULATO"
Thomas Pons,

Trovo questa discussione molto utile stackoverflow.com/questions/15666048/…
Anand Gupta

2
Ci sono alcune buone risposte anche qui .
Mistalis,

Risposte:


280

Spiegazione

Hai cose diverse qui:

Primo:

  • Se usi un servizio otterrai l'istanza di una funzione ("this " parola chiave).
  • Se si utilizza una factory, si otterrà il valore restituito richiamando il riferimento della funzione (l'istruzione return in factory).

rif: angular.service vs angular.factory

Secondo:

Tieni presente che tutti i fornitori di AngularJS (valore, costante, servizi, fabbriche) sono singoli!

Terzo:

L'uso dell'uno o dell'altro (servizio o fabbrica) riguarda lo stile del codice. Ma il modo comune in AngularJS è usare la fabbrica .

Perché ?

Perché "Il metodo factory è il modo più comune di inserire oggetti nel sistema di iniezione di dipendenza AngularJS. È molto flessibile e può contenere una sofisticata logica di creazione. Dato che le fabbriche sono funzioni regolari, possiamo anche sfruttare un nuovo ambito lessicale per simulare" privato "variabili. Questo è molto utile in quanto possiamo nascondere i dettagli di implementazione di un determinato servizio."

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


uso

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

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

Quindi, usa una fabbrica quando hai una logica complessa nel tuo servizio e non vuoi esporre questa complessità .

In altri casi, se si desidera restituire un'istanza di un servizio, utilizzare semplicemente il servizio .

Ma vedrai con il tempo che utilizzerai factory nell'80% dei casi, credo.

Per maggiori dettagli: http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/


AGGIORNARE :

Ottimo post qui: http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html

"Se vuoi che la tua funzione venga chiamata come una normale funzione , usa factory . Se vuoi che la tua funzione venga istanziata con il nuovo operatore, usa il servizio. Se non conosci la differenza, usa factory."


AGGIORNARE :

Il team di AngularJS fa il suo lavoro e fornisce una spiegazione: http://docs.angularjs.org/guide/providers

E da questa pagina:

"Factory e Service sono le ricette più utilizzate. L'unica differenza è che la ricetta di Service funziona meglio per oggetti di tipo personalizzato, mentre Factory può produrre primitive e funzioni JavaScript."


7
Per prima cosa: l'ho letto ovunque ma non capisco le implicazioni pratiche di esso. Immagino che dalla tua risposta non vi sia alcuna differenza pratica "per la maggior parte"? Grazie comunque per il libro ref!
user1941747

È semplice se il tuo servizio è davvero complesso e hai bisogno di metodi e oggetti privati ​​che usano una fabbrica
Thomas Pons,

1
Ho notato che hai aggiunto "Se vuoi restituire un'istanza di un servizio, usa semplicemente il servizio". La mia domanda di follow-up sarebbe QUANDO vuoi restituire un'istanza di un servizio? Sto cercando di trovare un caso d'uso specifico qui.
user1941747

12
"Poiché le fabbriche sono funzioni regolari, possiamo anche trarre vantaggio da un nuovo ambito lessicale per simulare variabili" private "." - questo non è specifico per le fabbriche, puoi fare lo stesso con i servizi ..
pootzko,

Sembra che il team di Google preferisca il servizio alla fabbrica, questo rende le cose ancora più confuse! google-styleguide.googlecode.com/svn/trunk/…
xzhang

111

originariamente allernhwkim ha pubblicato una risposta a questa domanda collegandola al suo blog , tuttavia un moderatore l'ha cancellata. È l'unico post che ho trovato che non ti dice solo come fare la stessa cosa con servizio, fornitore e fabbrica, ma ti dice anche cosa puoi fare con un fornitore che non puoi con una fabbrica e con una fabbrica che non puoi con un servizio.

Direttamente dal suo 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;
    }      
});

Questo mostra come CarService produrrà sempre un'auto con 4 cilindri, non è possibile cambiarla per le singole auto. Considerando che CarFactory restituisce una funzione che puoi fare new CarFactorynel tuo controller, passando un numero di cilindri specifici per quella macchina. Non puoi farlo new CarServiceperché CarService è un oggetto non una funzione.

I motivi per cui le fabbriche non funzionano in questo modo:

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

E restituire automaticamente una funzione che puoi istanziare, è perché quindi non puoi farlo (aggiungi cose al prototipo / ecc.):

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

Guarda come è letteralmente una fabbrica che produce un'auto.

La conclusione dal suo blog è abbastanza buona:

In conclusione,

---------------------------------------------------  
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------  
| Factory | Yes      | Yes          | No          |
---------------------------------------------------  
| Service | Yes      | No           | No          |
---------------------------------------------------  
| Provider| Yes      | Yes          | Yes         |       
---------------------------------------------------  
  1. Utilizzare il servizio quando è necessario solo un oggetto semplice come un hash, ad esempio {foo; 1, bar: 2} È facile codificare, ma non è possibile istanziarlo.

  2. Utilizzare Factory quando è necessario creare un'istanza di un oggetto, ad esempio un nuovo cliente (), un nuovo commento (), ecc.

  3. Utilizzare il provider quando è necessario configurarlo. vale a dire url di prova, url di qualità, url di produzione.

Se scopri che stai solo restituendo un oggetto in fabbrica, probabilmente dovresti usare il servizio.

Non farlo:

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

Usa invece il servizio:

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

11
è veramente utile per me. +1 per la tabella di confronto
Vu Anh,

5
se si definisce la funzione di servizio con un parametro numCylinder, avrà la stessa flessibilità del metodo di fabbrica
Ovi

vai a leggere il post blog e perdi il tuo tempo cercando di capire angolare, se conosci javascript dopo aver letto questo post capirai totalmente la differenza tra questo.
ncubica,

4
Molto sorpreso ! Stai riferendo un blog qui ed entrambi stanno dicendo cose completamente opposte. Tu dici: Fabbrica - Istantanea - Sì Blog dice: Fabbrica - Istantanea - No
Devesh M

1
Sono d'accordo con @Devesh. Penso che tu abbia confuso le istanze. Dal post del blog: "Solo con factory, non è possibile raggiungere questo obiettivo perché non è possibile creare un'istanza di factory".
Matt,

20

Il concetto per tutti questi provider è molto più semplice di quanto sembri inizialmente. Se si seziona un fornitore e si estrae le diverse parti, diventa molto chiaro.

Per dirla semplicemente ognuno di questi fornitori è una versione specializzata di l'altro, in questo ordine: provider> factory> value/ constant/ service.

Per così tanto tempo il provider fa quello che puoi, puoi usarlo più in basso nella catena, il che porterebbe a scrivere meno codice. Se non soddisfa ciò che desideri, puoi andare su per la catena e dovrai solo scrivere più codice.

Questa immagine illustra cosa intendo, in questa immagine vedrai il codice per un fornitore, con le parti evidenziate che mostrano quali parti del fornitore potrebbero essere utilizzate per creare una fabbrica, un valore, ecc.

I fornitori, le fabbriche, i servizi, ecc. Di AngularJS sono tutti la stessa cosa
(fonte: simplygoodcode.com )

Per maggiori dettagli ed esempi dal post sul blog da cui ho ottenuto l'immagine, visitare: http://www.simplygoodcode.com/2015/11/the-difference-b Between-service-provider-and-factory-in- angularjs/


8

Sia la fabbrica che il servizio generano oggetti singleton che possono essere configurati dai provider e iniettati in controller ed eseguono blocchi. Dal punto di vista dell'ingiunto, non vi è assolutamente alcuna differenza se l'oggetto provenga da una fabbrica o da un servizio.

Quindi, quando usare una fabbrica e quando usare un servizio? Si riduce alle tue preferenze di codifica e nient'altro. Se ti piace il modello JS modulare, vai in fabbrica. Se ti piace lo stile della funzione di costruzione ("classe"), scegli il servizio. Si noti che entrambi gli stili supportano membri privati.

Il vantaggio del servizio potrebbe essere che è più intuitivo dal punto di vista OOP: creare una "classe" e, in collaborazione con un provider, riutilizzare lo stesso codice tra i moduli e variare il comportamento degli oggetti istanziati semplicemente fornendo parametri diversi dal costruttore in un blocco di configurazione.


Potresti fornire un esempio di cosa intendi fornendo parametri diversi al costruttore in un blocco di configurazione? Come si forniscono i parametri se si tratta solo di un servizio o di una fabbrica. Cosa intendi con "in collaborazione con un fornitore"? Essere in grado di configurarlo mi fa pensare che molti dei miei oggetti dovrebbero essere fornitori contro fabbriche o servizi.
timbrown,

2

Non c'è nulla che una Fabbrica non possa fare o fare meglio rispetto a un Servizio. E viceversa. La fabbrica sembra essere più popolare. La ragione di ciò è la sua praticità nel gestire membri privati ​​/ pubblici. Il servizio sarebbe più goffo in questo senso. Quando si codifica un servizio, si tende a rendere pubblici i membri dell'oggetto tramite "questa" parola chiave e si potrebbe improvvisamente scoprire che tali membri pubblici non sono visibili a metodi privati ​​(ovvero funzioni interne).

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 utilizza la "nuova" parola chiave per creare un servizio per te, quindi l'istanza che Angular passa al controller avrà lo stesso inconveniente. Naturalmente puoi superare il problema usando questo / che:

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'  

Ma con una costante di servizio di grandi dimensioni, ciò renderebbe il codice scarsamente leggibile. Inoltre, i prototipi del servizio non vedranno membri privati, ma solo il pubblico sarà disponibile per loro:

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'

Riassumendo, usare Factory è più conveniente. Poiché Factory non presenta questi inconvenienti. Consiglierei di usarlo per impostazione predefinita.


Questa risposta ha diversi problemi. Innanzitutto, questo post dimostra il concetto di Javascript di scoping lessicale piuttosto che il funzionamento dei servizi AngularJS. Secondo, myapp.service(...)manca completamente il contesto della chiamata . Dove new Service()dovrebbe essere chiamato, nella funzione di servizio o nel punto in cui viene iniettato il servizio. Il terzo elenco non è semplicemente possibile nel contesto di myapp.service ('Service', function() {...}).
lanoxx,

2

Anche quando dicono che tutti i servizi e le fabbriche sono singleton, non sono d'accordo al 100%. Direi che le fabbriche non sono singoli e questo è il punto della mia risposta. Vorrei davvero pensare al nome che definisce ogni componente (Service / Factory), intendo:

Una fabbrica perché non è un singleton, puoi crearne quanti ne vuoi quando inietti, quindi funziona come una fabbrica di oggetti. Puoi creare una factory di un'entità del tuo dominio e lavorare più comodamente con questi oggetti che potrebbero essere come un oggetto del tuo modello. Quando recuperi diversi oggetti, puoi mapparli in questi oggetti e può agire in modo simile a un altro livello tra il modello DDBB e il modello AngularJs. Puoi aggiungere metodi agli oggetti in modo da orientarti un po 'di più sull'app AngularJs.

Nel frattempo un servizio è un singleton, quindi possiamo creare solo 1 di un tipo, forse non creare ma abbiamo solo 1 istanza quando iniettiamo in un controller, quindi un servizio fornisce più come un servizio comune (chiamate di riposo, funzionalità ..) ai controller.

Concettualmente puoi pensare che i servizi forniscano un servizio, le fabbriche possono creare più istanze (oggetti) di una classe


0

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 condividere 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.

uso : potrebbe essere utile per restituire una funzione 'class' che può 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 in tutti i progetti? Ancora un po 'confuso su questo.


0

Puoi usare entrambi nel modo che preferisci : sia che tu crei un oggetto o j ust per accedere alle funzioni da entrambi


È possibile creare un nuovo oggetto dal servizio

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

Nota :

  • il servizio di default restituisce oggetto e non funzione di costruzione.
  • Ecco perché la funzione di costruzione è impostata sulla proprietà this.model.
  • A causa di questo servizio restituirà l'oggetto, ma ma all'interno di quell'oggetto ci sarà la funzione di costruzione che verrà utilizzata per creare un nuovo oggetto;

È possibile creare un nuovo oggetto dalla fabbrica

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

Nota :

  • factory per impostazione predefinita restituisce la funzione di costruzione e non l'oggetto.
  • Ecco perché è possibile creare un nuovo oggetto con la funzione di costruzione.

Crea un servizio per accedere solo a funzioni semplici

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

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

Crea factory per accedere solo a funzioni semplici

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

Conclusione :

  • puoi usare sia il modo in cui desideri sia per creare un nuovo oggetto o semplicemente per accedere a semplici funzioni
  • Non ci sarà alcun hit di performance, usandone uno sopra l'altro
  • Entrambi sono oggetti singleton e viene creata solo un'istanza per app.
  • Essere solo un'istanza ogni dove viene passato il loro riferimento.
  • Nella documentazione angolare, la fabbrica è chiamata servizio e anche il servizio è chiamato servizio .

0

Fabbrica e assistenza sono il metodo più comunemente usato. L'unica differenza è che il metodo di servizio funziona meglio per gli oggetti che richiedono una gerarchia di ereditarietà, mentre Factory può produrre primitive e funzioni JavaScript.

La funzione Provider è il metodo principale e tutti gli altri sono solo zucchero sintattico. Ne hai bisogno solo se stai costruendo un pezzo di codice riutilizzabile che richiede una configurazione globale.

Esistono cinque metodi per creare servizi: Valore, Fabbrica, Servizio, Fornitore e Costante. Puoi saperne di più su questo qui servizio angolare , questo articolo spiega tutti questi metodi con esempi dimostrativi pratici.

.

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.