Confundido sobre Servicio vs Fábrica


618

Según tengo entendido, cuando dentro de una fábrica devuelvo un objeto que se inyecta en un controlador. Cuando estoy dentro de un servicio, estoy tratando con el objeto usando thisy sin devolver nada.

Supuse que un servicio siempre era un singleton y que se inyectaba un nuevo objeto de fábrica en cada controlador. Sin embargo, como resultado, ¿un objeto de fábrica también es un singleton?

Código de ejemplo para demostrar:

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

Al cambiar user.firsten ACtrlresulta que user.firsten BCtrltambién se cambia, por ejemplo, Useres un producto único?

¿Supuse que se inyectó una nueva instancia en un controlador con una fábrica?


44
Junto a "module.service" y "module.factory" hay 2 formas más de crear servicios en AngularJS. Para obtener más información, consulte la publicación del blog: " Cómo crear servicios AngularJS (singleton) de 4 formas diferentes "
Emil van Galen

Respuestas:


600

Todos los servicios angulares son singletons :

Documentos (ver Servicios como singletons ): https://docs.angularjs.org/guide/services

Por último, es importante darse cuenta de que todos los servicios de Angular son aplicaciones únicas. Esto significa que solo hay una instancia de un servicio determinado por inyector.

Básicamente, la diferencia entre el servicio y la fábrica es la siguiente:

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

Vea esta presentación sobre $ provide: http://slides.wesalvaro.com/20121113/#/

Esas diapositivas se usaron en una de las reuniones de AngularJs: http://blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html


13
Consulte también stackoverflow.com/questions/15666048/… que analiza las diferencias entre servicio, fábrica y servicio.
Mark Rajcok

31
El documento oficial indirectamente [sic! no está lo suficientemente claro] implica que incluso si define el servicio con la fábrica, se crea solo una vez. En otras palabras, NO se crea de nuevo según la referencia (punto de inyección), como se llame. Ambas formas dan como resultado una instancia de singleton por inyector.
honzajde

3
Usted dice "el servicio es solo una función constructora que se llamará con 'nuevo'", pero creo que eso es engañoso. No creo que se llame con nuevo detrás de escena, creo que el desarrollador es responsable de llamarlo new.
Tim Kindberg

55
@nfiniteloop, verifique el código fuente cerca de la línea 3574. Las fábricas son el método $ get del proveedor, y los servicios generan fábricas utilizando un método que llama a $ injector.instantiate en la función proporcionada, que luego llama a new. ( Ver documentos )
ciudadanoslave

14
Tenía la impresión de que un servicio era tan único que usted utilizaba al obtener una referencia a él. Y que una fábrica era un singleton que devolvía un nuevo objeto cada vez. Es decir, un servicio le daría un "auto" y todo en su proyecto usaría este auto. Mientras que una fábrica te daría un auto nuevo cada vez que invocases la fábrica. Uno era un singleton que devolvía un singleton y otro era un singleton que devolvía un objeto. ¿Alguien puede explicar? Llamar a todo un singleton no ayuda, ya que puede referirse a varias cosas.
user2483724

380

Para mí, la revelación llegó cuando me di cuenta de que todos funcionan de la misma manera: ejecutando algo una vez , almacenando el valor que obtienen, y luego tose ese mismo valor almacenado cuando se hace referencia a través de la inyección de dependencia.

Digamos que tenemos:

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

La diferencia entre los tres es que:

  1. aEl valor almacenado proviene de la ejecución fn, en otras palabras:fn()
  2. bEl valor almacenado proviene de newing fn, en otras palabras:new fn()
  3. cEl valor almacenado proviene de obtener primero una instancia newing fny luego ejecutar un $getmétodo de la instancia

lo que significa que hay algo así como un objeto de caché dentro de angular, cuyo valor de cada inyección solo se asigna una vez, cuando se inyectaron la primera vez y donde:

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

Es por eso que usamos thisen servicios y definimos a this.$geten proveedores.

Espero que esto ayude.


54
finalmente, una explicación sensata. Angular es una locura y tan grave que duele.
osiris

8
Esta debería ser la respuesta aceptada, ya que en realidad responde a la pregunta de POR QUÉ las fábricas, los servicios y los proveedores devuelven valores únicos. Las otras respuestas explican la diferencia entre fábricas, servicios y proveedores, pero nunca tocan el aspecto singleton.
wmock

3
Me gusta esto ... Cuando leo las mil líneas de oración de otro blogger ... solo logro entender la fábrica. Pero leí esto ... entiendo todo 3.
tsohtan

@osiris estoy de acuerdo. No me gusta Simplemente se siente tan estrechamente acoplado que hace rechinar mis dientes.
Thomas

2
Entonces, ¿debe proporcionar una implementación de $ get al usar proveedores?
Victor

95

ejemplo en vivo

ejemplo de "hola mundo"

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

También hay una manera de devolver una función de constructor para que pueda devolver clases nuevas en fábricas, como esta:

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

Entonces puede hacer esto en un controlador, que usa MyObjectWithParam:

var obj = new MyObjectWithParam("hello"),

Vea aquí el ejemplo completo:
http://plnkr.co/edit/GKnhIN?p=preview

Y aquí las páginas del grupo de Google, donde se discutió:
https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ


Tengo problemas con la minificación con tu ejemplo. ¿Sabes cómo debo anotar esto?
Pal

2
Sí, existe una notación minificada para Angular. Debería ser algo como esto: App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); Lea más sobre esto aquí: docs.angularjs.org/tutorial/step_05
JustGoscha

44
¿por qué querrías hacer esto, si puedes usarlo .serviceen su lugar?
flup

Tuve el mismo pensamiento @flup. @justgoscha, ¿hay algún beneficio ( percibido? ) de usar .factoryen lugar de .service?
xandercoded

55
Creo que porque un servicio es un singleton . Lo que construí aquí es básicamente una clase que es renovable. Por lo tanto, puede tener algo como una fábrica de servicios de automóviles y luego hacer new Car('BMW')y new Car('Ford')no comparten las mismas variables y todo.
JustGoscha

51

Aquí están las principales diferencias:

Servicios

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

Resultado: al declarar serviceName como un argumento inyectable, se le proporcionará la instancia de una función pasada a module.service.

Uso: podría ser útil para compartir funciones de utilidad que son útiles para invocar simplemente agregando () a la referencia de función inyectada. También se puede ejecutar con injectedArg.call( this )o similar.

Suerte

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

Resultado: al declarar factoryName como argumento inyectable, se le proporcionará el valor que se devuelve invocando la referencia de función que se le pasó module.factory.

Uso: podría ser útil para devolver una función de 'clase' que luego se puede actualizar para crear instancias.

También verifique la documentación de AngularJS y una pregunta similar sobre stackoverflow confundido sobre el servicio frente a la fábrica .

Aquí hay un ejemplo de uso de servicios y fábrica . Lea más sobre el servicio AngularJS vs fábrica .


66
Esto tiene sentido para mí. La fábrica devuelve el plan para crear nuevos objetos.

27

Agregando a la primera respuesta, creo que .service () es para las personas que han escrito su código en un estilo más orientado a objetos (C # / Java) (usando esta palabra clave y instanciando objeto a través de la función prototipo / Constructor).

Factory es para desarrolladores que escriben código que es más natural para JavaScript / estilo funcional de codificación.

Eche un vistazo al código fuente de .service y .factory method dentro de angular.js - internamente todos llaman método de proveedor:

  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

Muy simple:

.service: la función registrada se invocará como un constructor (también conocido como 'nuevo')

.factory: la función registrada se invocará como una función simple

Ambos se invocan una vez, lo que da como resultado un objeto singleton que se inyecta en otros componentes de su aplicación.


66
si. no hagamos las cosas más complicadas de lo que realmente son
flup

20

Todos los proveedores trabajan de la misma manera. Los diferentes métodos service, factory, providersolo permiten obtener el mismo resultado en menos código.

PD También hay valuey constant.

Cada caso especial en la cadena que comienza providery termina con valuetiene una limitación adicional. Entonces, para decidir entre ellos, debe preguntarse qué le permite lograr lo que desea con menos código.

Aquí hay una imagen que muestra lo que quiero decir:

ingrese la descripción de la imagen aquí

Puede obtener un desglose y una guía de referencia en la publicación del blog. Obtuve esta imagen de:

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


Se dice que los servicios son singleton, pero ¿por qué es singleton, si se crea una nueva instancia cada vez que la inyecto?
Ankur Marwaha

1
@AnkurMarwaha No se crea una nueva instancia cada vez, solo se crea una vez y se almacena en caché por AngularJS. Esto es cierto si está utilizando un proveedor, fábrica, servicio, etc. Puede confirmar esto usando console.log()e inyectando en múltiples controladores.
Luis Perez

Luis, su comentario entra en conflicto con la respuesta aceptada como dice: por último, es importante darse cuenta de que todos los servicios angulares son aplicaciones únicas. Esto significa que solo hay una instancia de un servicio determinado por inyector.
Ankur Marwaha

@AnkurMarwaha tal vez estoy malinterpretando algo. Usted citó "es importante darse cuenta de que todos los servicios de Angular son aplicaciones únicas"; el hecho de que sean aplicaciones únicas significa que solo se crean una vez. Que es lo que dije " No se crea una nueva instancia cada vez, solo se crea una vez y se almacena en caché ...". ¿Puedes señalar con más detalle dónde ves el conflicto?
Luis Perez

1
Ah, veo la confusión. El "inyector" es un objeto en angular. Se encarga de hacer la "inyección". Ejemplo, cuando el controlador se ejecuta por primera vez, el "inyector" observa los parámetros e inyecta cada uno. Solo hay un "inyector" para toda su aplicación. Una vez que el inyector crea una fábrica o servicio en particular, mantiene una instancia y lo reutiliza, de ahí el singleton. Por lo tanto, solo hay un inyector por aplicación y solo una instancia de un servicio determinado por inyector. La mayoría de aplicaciones angular sólo tienen una aplicación, por lo tanto, un inyector, por lo tanto, una instancia de cualquier servicio, controlador, etc.
Luis Pérez

13

Aquí hay algunos ejemplos más de servicios vs fábricas que pueden ser útiles para ver la diferencia entre ellos. Básicamente, un servicio tiene "nuevo ..." llamado, ya está instanciado. Una fábrica no se instancia automáticamente.

Ejemplos básicos

Devuelve un objeto de clase que tiene un método único

Aquí hay un servicio que tiene un único método:

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

Aquí hay una fábrica que devuelve un objeto con un método:

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

Devuelve un valor

Una fábrica que devuelve una lista de números:

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

console.log(NumberListFactory);

Un servicio que devuelve una lista de números:

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

console.log(NumberLister.numbers);

La salida en ambos casos es la misma, la lista de números.

Ejemplos avanzados

Variables de "clase" utilizando fábricas

En este ejemplo definimos un CounterFactory, incrementa o disminuye un contador y puede obtener el conteo actual u obtener cuántos objetos CounterFactory se han creado:

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

})

Usamos el CounterFactorypara crear múltiples contadores. Podemos acceder a la variable de clase para ver cuántos contadores se crearon:

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

La salida de este código es:

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

es un ejemplo útil, number_of_counter_factories es como un meta atributo de la clase CounterFactory, ¿verdad ?, entiendo que este ejemplo es replicable en un servicio (dime si estoy equivocado), ¿cuál sería la diferencia semántica en este caso?
geoom

Ejemplo útil! Entonces, esto básicamente significa que en una fábrica puede tener esa capa adicional de abstracción que no entraría en un servicio. Sin embargo, sea lo que sea que se devuelva, se devolverá una nueva instancia cada vez que se use 'nuevo'. Cualquier variable que no se declare dentro del bloque de retorno será singleton. ¿Lo entendí bien?
Swanidhi

@Swanidhi básicamente sí, puede declarar variables que son singletons en la fábrica. Por eso los llamé variables de "clase".

13

"Fábrica" ​​y "Servicio" son diferentes formas de hacer DI (inyección de dependencia) en angular.

Entonces, cuando definimos DI usando "servicio" como se muestra en el código a continuación. Esto crea una nueva instancia GLOBAL del objeto "Logger" y la inyecta en la función.

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

Cuando define DI utilizando una "fábrica", no crea una instancia. Simplemente pasa el método y luego el consumidor internamente tiene que hacer llamadas a la fábrica para instancias de objetos.

app.factory("Customerfactory", CreateCustomer);

A continuación se muestra una imagen simple que muestra visualmente cómo el proceso de DI para "Servicio" es diferente de "Fábrica".

ingrese la descripción de la imagen aquí

Se debe usar Factory Cuando queremos crear diferentes tipos de objetos dependiendo de los escenarios. Por ejemplo, dependiendo del escenario, queremos crear un simple objeto "Cliente", o "Cliente" con objeto "Dirección" o "Cliente" con objeto "Teléfono". Aquí hay una explicación detallada de este párrafo.

El servicio debe usarse cuando tenemos utilidades o funciones compartidas para inyectar como utilidad, registrador, controlador de errores, etc.


Cada respuesta que he visto sobre esta pregunta y otras similares está especificando la diferencia en mecánica y sintaxis. Esta respuesta da una razón real por la que seleccionaría uno sobre el otro. Es una cuestión de semántica y mirar el nombre, servicio o fábrica, comunica su propósito y cómo se usan.
Joe Mayo

8

Estilo de servicio : ( probablemente el más simple ) devuelve la función real: útil para compartir funciones de utilidad que son útiles para invocar simplemente agregando () a la referencia de función inyectada.

Un servicio en AngularJS es un objeto JavaScript singleton que contiene un conjunto de funciones

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

});

Estilo de fábrica : ( más complicado pero más sofisticado ) devuelve el valor de retorno de la función: instanciar un objeto como nuevo Object () en java.

La fábrica es una función que crea valores. Cuando un servicio, controlador, etc. necesita un valor inyectado de una fábrica, la fábrica crea el valor a pedido. Una vez creado, el valor se reutiliza para todos los servicios, controladores, etc. que lo necesitan inyectado.

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

});

Estilo del proveedor : ( versión completa, configurable ) devuelve el resultado de la función $ get de la función: Configurable.

Los proveedores en AngularJS son la forma más flexible de fábrica que puede crear. Usted registra un proveedor con un módulo tal como lo hace con un servicio o fábrica, excepto que utiliza la función de proveedor () en su lugar.

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 diferencia básica es que el proveedor permite establecer valores primitivos (no objetos), de matriz o de función de devolución de llamada en la variable declarada de fábrica y, por lo tanto, si devuelve un objeto, debe declararse y devolverse explícitamente.

Por otro lado, un servicio solo se puede usar para establecer la variable declarada de servicio en un objeto, por lo que podemos evitar la creación explícita y la devolución de los objetos, mientras que, por otro lado, permite el uso de esta palabra clave.

O, en pocas palabras, "el proveedor es una forma más genérica, mientras que el servicio se limita a objetos solamente".


2

Así es como entendí la diferencia entre ellos en términos de patrones de diseño:

Servicio : Devuelve un tipo, que se renovará para crear un objeto de ese tipo. Si se utiliza la analogía Java, el Servicio devuelve una definición de Clase Java .

Fábrica : Devuelve un objeto concreto que puede usarse inmediatamente. En Java Analogy, Factory devuelve un objeto Java .

La parte que a menudo confunde a las personas (incluido yo mismo) es que cuando se inyecta un Servicio o una Fábrica en su código, se pueden usar de la misma manera, lo que se obtiene en su código en ambos casos es un objeto concreto que puede invocar de inmediato. Lo que significa que en el caso del Servicio, angular llama "nuevo" en la declaración del servicio en su nombre. Creo que este es un concepto complicado.


1

Esta sería la mejor y breve respuesta para comprender el servicio Vs Factory Vs Provider

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

Aquí lo que dice Ben con una demostración http://jsbin.com/ohamub/1/edit?html,output

"Hay comentarios en el código que ilustran las principales diferencias, pero las expondré un poco aquí. Como nota, solo estoy entendiendo esto, así que si digo algo que está mal, avíseme.

Servicios

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

Resultado : al declarar serviceName como argumento inyectable, se le proporcionará la referencia de función real que se pasó a module.service.

Uso : podría ser útil para compartir funciones de utilidad que son útiles para invocar simplemente agregando () a la referencia de función inyectada. También se puede ejecutar con injectedArg.call (this) o similar.

Suerte

Sintaxis : module.factory ('factoryName', función);

Resultado : al declarar factoryName como argumento inyectable, se le proporcionará el valor que se devuelve invocando la referencia de función pasada a module.factory.

Uso : podría ser útil para devolver una función de 'clase' que luego se puede actualizar para crear instancias.

Proveedores

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

Resultado : al declarar providerName como argumento inyectable, se le proporcionará el valor que se devuelve invocando el método $ get de la referencia de función pasada a module.provider.

Uso : podría ser útil para devolver una función de 'clase' que luego se puede actualizar para crear instancias, pero que requiere algún tipo de configuración antes de ser inyectada. ¿Quizás útil para clases que son reutilizables en proyectos? Todavía un poco confuso en este caso "Ben


1

Tuve esta confusión por un tiempo y estoy haciendo mi mejor esfuerzo para proporcionar una explicación simple aquí. Espero que esto ayude!

angular .factoryy angular .serviceambos se usan para inicializar un servicio y trabajar de la misma manera.

La única diferencia es cómo desea inicializar su servicio.

Ambos son Singletons


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


Fábrica

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

Si desea inicializar su servicio desde una función que tiene con un valor de retorno , debe utilizar este factorymétodo.

p.ej

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

app.factory('myService', myService);

Al inyectar este servicio (por ejemplo, a su controlador):

  • Angular llamará a su función dada (as myService()) para devolver el objeto
  • Singleton : se llama solo una vez, se almacena y pasa el mismo objeto.


Servicio

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

Si desea inicializar su servicio desde una función de constructor (usando una thispalabra clave), debe usar este servicemétodo.

p.ej

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

app.service('myService', myService);

Al inyectar este servicio (por ejemplo, a su controlador):

  • Angular newutilizará su función (as new myService()) para devolver el objeto
  • Singleton : se llama solo una vez, se almacena y pasa el mismo objeto.


NOTA: Si usa factorycon <constructor function>o servicecon <function with a return value>, no funcionará.


Ejemplos: demostraciones


1

Esto es lo que me ayudó a entender la diferencia, gracias a una publicación de blog de Pascal Precht.

Un servicio es un método en un módulo que toma un nombre y una función que define el servicio. Puede inyectar y usar ese servicio en particular en otros componentes, como controladores, directivas y filtros. Una fábrica es un método en un módulo y también toma un nombre y una función que define la fábrica. También podemos inyectar y usarlo de la misma manera que lo hicimos con el servicio.

Los objetos creados con nuevo usan el valor de la propiedad prototipo de su función de constructor como su prototipo, por lo que encontré el código angular que llama a Object.create (), que creo que es la función de constructor de servicios cuando se instancia. Sin embargo, una función de fábrica es realmente solo una función que se llama, por lo que tenemos que devolver un objeto literal para la fábrica.

Aquí está el código angular 1.5 que encontré para la fábrica:

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

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

Fragmento de código fuente angular para la función factory ():

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

Toma el nombre y la función de fábrica que se pasa y devuelve un proveedor con el mismo nombre, que tiene un método $ get que es nuestra función de fábrica. Cada vez que le pide al inyector una dependencia específica, básicamente le pide al proveedor correspondiente una instancia de ese servicio, llamando al método $ get (). Es por eso que se requiere $ get () al crear proveedores.

Aquí está el código angular 1.5 para servicio.

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

¡Resulta que cuando llamamos al servicio (), en realidad llama a la fábrica ()! Sin embargo, no solo pasa nuestra función de constructor de servicios a la fábrica tal como está. También pasa una función que le pide al inyector que cree una instancia de un objeto por el constructor dado.

En otras palabras, si inyectamos MyService en algún lugar, lo que sucede en el código es:

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

Para volver a expresarlo, un servicio llama a una fábrica, que es un método $ get () en el proveedor correspondiente. Además, $ injector.instantiate () es el método que finalmente llama a Object.create () con la función de constructor. Es por eso que usamos "esto" en los servicios.

Para ES5, no importa cuál usemos: service () o factory (), siempre se llama una fábrica que crea un proveedor para nuestro servicio.

Sin embargo, también puede hacer exactamente lo mismo con los servicios. Sin embargo, un servicio es una función constructora que no nos impide devolver literales de objeto. Por lo tanto, podemos tomar nuestro código de servicio y escribirlo de una manera que básicamente haga exactamente lo mismo que nuestra fábrica o, en otras palabras, puede escribir un servicio como fábrica para devolver un objeto.

¿Por qué la mayoría de la gente recomienda usar fábricas en lugar de servicios? Esta es la mejor respuesta que he visto que proviene del libro de Pawel Kozlowski: Dominar el desarrollo de aplicaciones web con AngularJS.

El método de fábrica es la forma más común de introducir objetos en el sistema de inyección de dependencia AngularJS. Es muy flexible y puede contener una lógica de creación sofisticada. Como las fábricas son funciones regulares, también podemos aprovechar un nuevo ámbito léxico para simular variables "privadas". Esto es muy útil ya que podemos ocultar los detalles de implementación de un servicio determinado ".


1
  • Con la fábrica , realmente crea un objeto dentro de la fábrica y lo devuelve.
  • Con el servicio , solo tiene una función estándar que utiliza la thispalabra clave para definir la función.
  • Con el proveedor hay una que $getusted define y puede usarse para obtener el objeto que devuelve los datos.

1

Hay tres formas de manejar la lógica de negocios en AngularJS: ( Inspirado en el curso Coursera AngularJS de Yaakov ) que son:

  1. Servicio
  2. Fábrica
  3. Proveedor

Aquí solo vamos a hablar de Servicio vs Fábrica

Servicio :

Sintaxis:

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>

Las principales características del servicio:

  1. Instancia perezosa : si el servicio no se inyecta, no se instanciará nunca. Entonces, para usarlo, deberá inyectarlo en un módulo.

  2. Singleton : si se inyecta en varios módulos, todos tendrán acceso a una sola instancia en particular. Por eso, es muy conveniente compartir datos entre diferentes controladores.

FÁBRICA

Ahora hablemos de la Fábrica en AngularJS

Primero echemos un vistazo a la sintaxis :

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

Ahora usando los dos anteriores en el controlador:

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

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

Características de la fábrica:

  1. Este tipo de servicios sigue el patrón de diseño de fábrica . La fábrica puede considerarse como un lugar central que crea nuevos objetos o métodos.

  2. Esto no solo produce singleton, sino también servicios personalizables.

  3. El .service()método es una fábrica que siempre produce el mismo tipo de servicio, que es un singleton. No hay una manera fácil de configurar su comportamiento. Ese .service()método generalmente se usa como un acceso directo para algo que no requiere ninguna configuración en absoluto.



0

Puede comprender la diferencia con esta analogía: considere la diferencia entre una función normal que devolverá algún valor y la función de constructor que se instanciará usando una nueva palabra clave, por lo que crear factory es similar a crear una función normal que devolverá algún valor (primitivo o un objeto), mientras que crear un servicio es como crear una función de constructor (clase OO) de la cual podemos crear una instancia usando una nueva palabra clave. Lo único que debe notar aquí es que cuando usamos el método de Servicio para crear servicios, creará automáticamente una instancia del mismo utilizando un mecanismo de inyección de dependencia compatible con AngularJS

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.