AngularJS: cuándo usar el servicio en lugar de la fábrica


296

Por favor tengan paciencia conmigo aquí. Sé que hay otras respuestas como: AngularJS: Servicio vs proveedor vs fábrica

Sin embargo, todavía no puedo entender cuándo usarías el servicio en la fábrica.

Por lo que puedo decir, la fábrica se usa comúnmente para crear funciones "comunes" que pueden ser llamadas por múltiples Controladores: Crear funciones comunes de controlador

Los documentos angulares parecen preferir la fábrica al servicio. ¡Incluso se refieren al "servicio" cuando usan la fábrica, lo cual es aún más confuso! http://docs.angularjs.org/guide/dev_guide.services.creating_services

Entonces, ¿cuándo se usaría el servicio?

¿Hay algo que solo sea posible o mucho más fácil con el servicio?

¿Hay algo diferente que ocurra detrás de escena? Diferencias de rendimiento / memoria?

Aquí hay un ejemplo. Aparte del método de declaración, parecen idénticos y no puedo entender por qué haría uno frente al otro. http://jsfiddle.net/uEpkE/

Actualización: Según la respuesta de Thomas, parece implicar que el servicio es para una lógica más simple y de fábrica para una lógica más compleja con métodos privados, por lo que actualicé el código de violín a continuación y parece que ambos son capaces de admitir funciones privadas.

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

por supuesto, el servicio es privado, pero si lees correctamente mi publicación es puramente estilo código: también podemos aprovechar un nuevo ámbito léxico para simular variables "privadas". Es "SIMULAR"
Thomas Pons

Esta discusión me parece muy útil stackoverflow.com/questions/15666048/…
Anand Gupta

Respuestas:


280

Explicación

Tienes cosas diferentes aquí:

Primero:

  • Si utiliza un servicio, obtendrá la instancia de una función ("this " palabra clave).
  • Si usa una fábrica, obtendrá el valor que se devuelve invocando la referencia de función (la declaración de devolución en la fábrica).

ref: angular.service vs angular.factory

Segundo:

¡Tenga en cuenta que todos los proveedores en AngularJS (valor, constante, servicios, fábricas) son singletons!

Tercero:

Usar uno u otro (servicio o fábrica) tiene que ver con el estilo de código. Pero, la forma común en AngularJS es usar la fábrica .

Por qué ?

Porque "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. Dado que las fábricas son funciones regulares, también podemos aprovechar un nuevo ámbito léxico para simular" privado "variables. Esto es muy útil ya que podemos ocultar los detalles de implementación de un servicio determinado".

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


Uso

Servicio: 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.

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

Por lo tanto, use una fábrica cuando tenga una lógica compleja en su servicio y no quiera exponer esta complejidad .

En otros casos, si desea devolver una instancia de un servicio, simplemente use el servicio .

Pero verás con el tiempo que usarás la fábrica en el 80% de los casos, creo.

Para más detalles: http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/


ACTUALIZACIÓN

Excelente publicación aquí: http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html

"Si desea que su función se llame como una función normal , use la fábrica . Si desea que su función sea instanciada con el nuevo operador, use el servicio. Si no conoce la diferencia, use la fábrica".


ACTUALIZACIÓN

El equipo de AngularJS hace su trabajo y da una explicación: http://docs.angularjs.org/guide/providers

Y desde esta página:

"Factory y Service son las recetas más utilizadas. La única diferencia entre ellas es que la receta de Service funciona mejor para objetos de tipo personalizado, mientras que Factory puede producir funciones y primitivas JavaScript".


77
Re Primero: lo leí en todas partes pero no entiendo las implicaciones prácticas del mismo. Supongo que por su respuesta no hay una diferencia práctica "en su mayor parte"? ¡Gracias por la referencia del libro!
user1941747

Es simple si su servicio es realmente complejo y necesita métodos y objetos privados para usar una fábrica
Thomas Pons

1
Noté que agregó "Si desea devolver una instancia de un servicio, simplemente use el servicio". Mi pregunta de seguimiento sería ¿CUÁNDO desea devolver una instancia de un servicio? Estoy tratando de encontrar un caso de uso específico aquí.
user1941747

12
"Dado que las fábricas son funciones regulares, también podemos aprovechar un nuevo ámbito léxico para simular variables" privadas ". - esto no es específico para las fábricas, puedes hacer lo mismo con los servicios ..
pootzko

Parece que el equipo de Google prefiere el servicio sobre la fábrica, ¡esto hace que las cosas sean aún más confusas! google-styleguide.googlecode.com/svn/trunk/…
xzhang

111

Allernhwkim originalmente publicó una respuesta a esta pregunta enlazando a su blog , pero un moderador la eliminó. Es la única publicación que he encontrado que no solo te dice cómo hacer lo mismo con el servicio, el proveedor y la fábrica, sino que también te dice qué puedes hacer con un proveedor que no puedes con una fábrica, y con Una fábrica que no se puede con un servicio.

Directamente desde su 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;
    }      
});

Esto muestra cómo CarService siempre producirá un automóvil con 4 cilindros, no puede cambiarlo por automóviles individuales. Mientras que CarFactory devuelve una función para que pueda hacerlo new CarFactoryen su controlador, pasando una serie de cilindros específicos para ese automóvil. No puede hacerlo new CarServiceporque CarService es un objeto, no una función.

La razón por la que las fábricas no funcionan así:

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

Y devolver automáticamente una función para que pueda crear una instancia, es porque entonces no puede hacer esto (agregue cosas al prototipo / etc.):

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

Vea cómo es, literalmente, una fábrica que produce un automóvil.

La conclusión de su blog es bastante buena:

En conclusión,

---------------------------------------------------  
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------  
| Factory | Yes      | Yes          | No          |
---------------------------------------------------  
| Service | Yes      | No           | No          |
---------------------------------------------------  
| Provider| Yes      | Yes          | Yes         |       
---------------------------------------------------  
  1. Use el Servicio cuando necesite solo un objeto simple como un Hash, por ejemplo {foo; 1, bar: 2} Es fácil de codificar, pero no puede crear una instancia.

  2. Use Factory cuando necesite crear una instancia de un objeto, es decir, un nuevo Cliente (), un nuevo Comentario (), etc.

  3. Use el proveedor cuando necesite configurarlo. es decir, url de prueba, url de control de calidad, url de producción.

Si descubres que solo estás devolviendo un objeto en fábrica, probablemente deberías usar el servicio.

No hagas esto:

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

Utilice el servicio en su lugar:

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

11
Es muy útil para mí. +1 para tabla de comparación
Vu Anh

55
si define la función de servicio con un parámetro numCylinder, tendrá la misma flexibilidad que el método de fábrica
Ovi

ve y lee el blog de la publicación, y pierde tu tiempo tratando de averiguar angular, si conoces JavaScript después de leer esta publicación, comprenderás totalmente la diferencia entre esto.
ncubica

44
Muy sorprendido ! Estás refiriendo un blog aquí y ambos dicen algo completamente opuesto. Usted dice: Fábrica - Instalable - Sí Blog dice: Fábrica - Instalable - No
Devesh M

1
Estoy de acuerdo con @Devesh. Creo que tienes las instancias mezcladas. De la publicación del blog: "Solo con la fábrica, no se puede lograr esto porque la fábrica no se puede instanciar".
Matt

20

El concepto para todos estos proveedores es mucho más simple de lo que parece inicialmente. Si disecciona a un proveedor y extrae las diferentes partes, queda muy claro.

En pocas palabras cada uno de estos proveedores es una versión especializada de la otra, en este orden: provider> factory> value/ constant/ service.

Mientras el proveedor haga lo que pueda, puede usar el proveedor más adelante en la cadena, lo que daría como resultado escribir menos código. Si no logra lo que desea, puede subir la cadena y solo tendrá que escribir más código.

Esta imagen ilustra lo que quiero decir, en esta imagen verá el código de un proveedor, con las partes resaltadas que le muestran qué partes del proveedor podrían usarse para crear una fábrica, valor, etc.

Los proveedores, fábricas, servicios, etc. de AngularJS son lo mismo
(fuente: simplygoodcode.com )

Para obtener más detalles y ejemplos de la publicación del blog de donde obtuve la imagen, vaya a: http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


8

Tanto la fábrica como el servicio dan como resultado objetos únicos que los proveedores pueden configurar e inyectar en controladores y ejecutar bloques. Desde el punto de vista del inyectado, no hay absolutamente ninguna diferencia si el objeto proviene de una fábrica o de un servicio.

Entonces, ¿cuándo usar una fábrica y cuándo usar un servicio? Se reduce a su preferencia de codificación, y nada más. Si te gusta el patrón JS modular, entonces ve a la fábrica. Si le gusta el estilo de la función de constructor ("clase"), vaya al servicio. Tenga en cuenta que ambos estilos admiten miembros privados.

La ventaja del servicio podría ser que es más intuitivo desde el punto de vista de OOP: cree una "clase" y, junto con un proveedor, reutilice el mismo código en todos los módulos y varíe el comportamiento de los objetos instanciados simplemente suministrando diferentes parámetros para el constructor en un bloque de configuración.


¿Podría proporcionar un ejemplo de lo que quiere decir con diferentes parámetros para el constructor en un bloque de configuración? ¿Cómo se proporcionan los parámetros si es solo un servicio o una fábrica? ¿Qué quiere decir con "en conjunto con un proveedor"? Ser capaz de configurarlo me hace pensar que muchos de mis objetos deberían ser proveedores o fábricas o servicios.
timbrown

2

No hay nada que una Fábrica no pueda hacer o haga mejor en comparación con un Servicio. Y viceversa. La fábrica parece ser más popular. La razón de esto es su conveniencia en el manejo de miembros privados / públicos. El servicio sería más torpe en este sentido. Al codificar un Servicio, tiende a hacer públicos los miembros de su objeto a través de "esta" palabra clave y de repente puede descubrir que esos miembros públicos no son visibles para los métodos privados (es decir, funciones internas).

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 utiliza la palabra clave "nueva" para crear un servicio para usted, por lo que la instancia que Angular pasa al controlador tendrá el mismo inconveniente. Por supuesto, puede superar el problema utilizando esto / aquello:

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'  

Pero con una gran constante de servicio, esto haría que el código fuera poco legible. Además, los prototipos del Servicio no verán miembros privados, solo públicos estarán disponibles para ellos:

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'

En resumen, usar Factory es más conveniente. Como Factory no tiene estos inconvenientes. Recomendaría usarlo por defecto.


Esta respuesta tiene varios problemas. Primero, esta publicación demuestra el concepto de alcance léxico de Javascript en lugar de cómo funcionan los servicios de AngularJS. Segundo, el contexto de la llamada myapp.service(...)falta por completo. Dónde se new Service()supone que debe llamarse, en la función de servicio o en el lugar donde se inyecta el Servicio. El tercer listado simplemente no es posible en el contexto de myapp.service ('Service', function() {...}).
lanoxx

2

Incluso cuando dicen que todos los servicios y fábricas son únicos, no estoy 100% de acuerdo con eso. Yo diría que las fábricas no son singletons y este es el punto de mi respuesta. Realmente pensaría en el nombre que define cada componente (Servicio / Fábrica), quiero decir:

Una fábrica porque no es un singleton, puede crear tantos como desee cuando se inyecta, por lo que funciona como una fábrica de objetos. Puede crear una fábrica de una entidad de su dominio y trabajar más cómodamente con estos objetos que podrían ser como un objeto de su modelo. Cuando recupera varios objetos, puede asignarlos en estos objetos y puede actuar como otra capa entre el DDBB y el modelo AngularJs. Puede agregar métodos a los objetos para que se oriente un poco más a su aplicación AngularJs.

Mientras tanto un servicio es un singleton, por lo que solo podemos crear 1 de un tipo, tal vez no crear, pero solo tenemos 1 instancia cuando inyectamos en un controlador, por lo que un servicio proporciona más como un servicio común (llamadas de descanso, funcionalidad ...) a los controladores.

Conceptualmente, puede pensar que los servicios brindan un servicio, las fábricas pueden crear múltiples instancias (objetos) de una clase


0

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 es un poco confuso en este caso.


0

Puede usar ambos de la forma que desee : ya sea crear un objeto o simplemente acceder a las funciones de ambos


Puedes crear un nuevo objeto desde el servicio

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 :

  • El servicio por defecto devuelve el objeto y no la función constructora.
  • Es por eso que la función de constructor se establece en esta propiedad de modelo.
  • Debido a este servicio devolverá el objeto, pero dentro de ese objeto habrá una función de constructor que se usará para crear un nuevo objeto;

Puedes crear un nuevo objeto de fábrica

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 :

  • La fábrica por defecto devuelve la función de constructor y no el objeto.
  • Por eso se puede crear un nuevo objeto con la función de constructor.

Crear servicio para acceder a funciones simples

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

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

Crear fábrica para acceder a funciones simples

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

Conclusión

  • puede usar la forma que desee, ya sea para crear un nuevo objeto o simplemente para acceder a funciones simples
  • No habrá ningún impacto en el rendimiento, usando uno sobre el otro
  • Ambos son objetos únicos y solo se crea una instancia por aplicación.
  • Siendo solo una instancia cada vez que se pasa su referencia.
  • En la documentación angular, la fábrica se llama servicio y también el servicio se llama servicio .

0

La fábrica y el servicio son el método más utilizado. La única diferencia entre ellos es que el método de servicio funciona mejor para los objetos que necesitan jerarquía de herencia, mientras que Factory puede producir funciones y primitivas de JavaScript.

La función de proveedor es el método principal y todos los demás son simplemente azúcar sintáctica. Solo lo necesita si está creando un código reutilizable que necesita una configuración global.

Existen cinco métodos para crear servicios: Valor, Fábrica, Servicio, Proveedor y Constante. Puede obtener más información sobre esto aquí servicio angular , este artículo explica todos estos métodos con ejemplos prácticos de demostración.

.

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.