AngularJS: Quando usar serviço em vez de fábrica

Por favor, tenha paciência comigo aqui. Eu sei que existem outras respostas como: AngularJS: Service vs provider vs factory

No entanto, ainda não consigo descobrir quando você usaria o serviço pela fábrica.

Pelo que eu posso dizer, a fábrica é comumente usada para criar funções “comuns” que podem ser chamadas por vários Controladores: Criando funções comuns do controlador

Os documentos angulares parecem preferir a fábrica ao serviço. Eles ainda se referem a “serviço” quando eles usam fábrica que é ainda mais confuso! http://docs.angularjs.org/guide/dev_guide.services.creating_services

Então, quando alguém usaria o serviço?

Existe algo que só é possível ou muito mais fácil com o serviço?

Existe algo diferente que acontece nos bastidores? Diferenças de desempenho / memory?

Aqui está um exemplo. Além do método de declaração, eles parecem idênticos e eu não consigo descobrir por que eu faria um contra o outro. http://jsfiddle.net/uEpkE/

Update: A partir da resposta de Thomas parece implicar que o serviço é para lógica mais simples e fábrica para lógica mais complexa com methods privados, então eu atualizei o código do violino abaixo e parece que ambos são capazes de suportar funções 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() ]; } 

Explicação

Você tem coisas diferentes aqui:

Primeiro:

  • Se você usar um serviço, obterá a instância de uma function (a palavra-chave ” this “).
  • Se você usar uma fábrica, obterá o valor retornado, invocando a referência de function (a declaração de retorno na fábrica).

ref: angular.service vs angular.factory

Segundo:

Tenha em mente que todos os provedores em AngularJS (valor, constante, serviços, fábricas) são singletons!

Terceiro:

Usando um ou outro (serviço ou fábrica) é sobre o estilo de código. Mas, o caminho comum no AngularJS é usar factory .

Por quê ?

Porque “O método factory é a maneira mais comum de colocar objects no sistema de injeção de dependência AngularJS. É muito flexível e pode conter lógica de criação sofisticada. Como as fábricas são funções regulares, também podemos aproveitar um novo escopo léxico para simular” private “variables. Isso é muito útil, pois podemos ocultar detalhes de implementação de um determinado serviço.”

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


Uso

Serviço: Pode ser útil para compartilhar funções de utilidade que são úteis para invocar simplesmente anexando () à referência de function injetada. Também pode ser executado com injectedArg.call(this) ou similar.

Fábrica: Pode ser útil para retornar uma function de ‘class’ que pode ser nova para criar instâncias.

Portanto, use uma fábrica quando você tiver uma lógica complexa em seu serviço e não quiser expor essa complexidade .

Em outros casos, se você quiser retornar uma instância de um serviço, basta usar o serviço .

Mas você verá com o tempo que você vai usar a fábrica em 80% dos casos, eu acho.

Para mais detalhes: http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/


ATUALIZAÇÃO:

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

“Se você quer que sua function seja chamada como uma function normal , use factory . Se você quer que sua function seja instanciada com o novo operador, use service. Se você não sabe a diferença, use factory.”


ATUALIZAÇÃO:

A equipe do AngularJS faz seu trabalho e dá uma explicação: http://docs.angularjs.org/guide/providers

E desta página:

“Fábrica e Serviço são as receitas mais usadas. A única diferença entre elas é que a receita do Serviço funciona melhor para objects do tipo personalizado, enquanto a Fábrica pode produzir primitivas e funções JavaScript.”

allernhwkim originalmente postou uma resposta sobre esta questão ligando para o seu blog , no entanto um moderador excluiu. É o único post que eu encontrei que não diz apenas como fazer a mesma coisa com serviço, provedor e fábrica, mas também diz o que você pode fazer com um provedor que você não pode com uma fábrica, e com uma fábrica que você não pode com um serviço.

Diretamente do seu 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; } }); 

Isso mostra como o CarService sempre produzirá um carro com 4 cilindros, você não pode trocá-lo por carros individuais. Considerando que o CarFactory retorna uma function para que você possa fazer uma new CarFactory no seu controlador, passando alguns cilindros específicos para esse carro. Você não pode fazer o new CarService porque o CarService é um object e não uma function.

As fábricas de razão não funcionam assim:

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

E automaticamente retorna uma function para você instanciar, é porque então você não pode fazer isso (adicionar coisas ao protótipo / etc):

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

Veja como é literalmente uma fábrica produzindo um carro.

A conclusão do blog dele é muito boa:

Em conclusão,

 --------------------------------------------------- | Provider| Singleton| Instantiable | Configurable| --------------------------------------------------- | Factory | Yes | Yes | No | --------------------------------------------------- | Service | Yes | No | No | --------------------------------------------------- | Provider| Yes | Yes | Yes | --------------------------------------------------- 
  1. Use o Service quando precisar apenas de um object simples, como um Hash, por exemplo {foo; 1, bar: 2} É fácil codificar, mas não é possível instanciá-lo.

  2. Use Factory quando precisar instanciar um object, ou seja, novo Customer (), novo Comment (), etc.

  3. Use o Provedor quando precisar configurá-lo. ou seja, URL de teste, URL de controle de qualidade, URL de produção.

Se você achar que está apenas retornando um object na fábrica, provavelmente deve usar o serviço.

Não faça isso:

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

Use o serviço em vez disso:

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

O conceito para todos esses provedores é muito mais simples do que parece inicialmente. Se você dissecar um provedor e retirar as diferentes partes, isso ficará muito claro.

Para simplificar, cada um desses provedores é uma versão especializada do outro, nesta ordem: provider > factory > value / constant / service .

Enquanto o provedor faz o que você pode, você pode usar o provedor mais abaixo na cadeia, o que resultaria em escrever menos código. Se não conseguir o que você quer, você pode subir na cadeia e você terá que escrever mais código.

Esta imagem ilustra o que quero dizer, nesta imagem você verá o código de um provedor, com as partes destacadas mostrando quais partes do provedor podem ser usadas para criar uma fábrica, valor, etc.

Fornecedores AngularJS, fábricas, serviços, etc, são a mesma coisa http://sofpt.miximages.com/angularjs/angularjs-provider-service-factory-highlight.png

Para mais detalhes e exemplos do post do blog onde eu tenho a imagem de ir para: http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/

Tanto a fábrica quanto o serviço resultam em objects singleton que podem ser configurados por provedores e injetados em controladores e em blocos de execução. Do ponto de vista do injetado, não há absolutamente nenhuma diferença se o object veio de uma fábrica ou de um serviço.

Então, quando usar uma fábrica e quando usar um serviço? Tudo se resume à sua preferência de codificação e nada mais. Se você gosta do padrão modular JS, vá para a fábrica. Se você gosta do estilo de function de construtor (“class”), vá para o serviço. Note que ambos os estilos suportam membros privados.

A vantagem do serviço pode ser que ele seja mais intuitivo do ponto de vista da OOP: crie uma “class” e, em conjunto com um provedor, reutilize o mesmo código em módulos e varie o comportamento dos objects instanciados simplesmente fornecendo parâmetros diferentes para o construtor em um bloco de configuração.

Não há nada que uma Fábrica não possa fazer ou faça melhor em comparação com um Serviço. E vice verso. Fábrica parece ser mais popular. A razão para isso é a conveniência de lidar com membros privados / públicos. O serviço seria mais desajeitado a esse respeito. Ao codificar um Serviço, você tende a tornar públicos os membros de seus objects através da palavra-chave “this” e pode subitamente descobrir que esses membros públicos não são visíveis a methods privados (isto é, funções 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 usa a palavra-chave “new” para criar um serviço para você, então a instância Angular que passa para o controlador terá a mesma desvantagem. Claro que você pode superar o problema usando isto / aquilo:

 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' 

Mas com uma grande constante de serviço, isso tornaria o código mal legível. Além disso, os protótipos do Serviço não verão membros privados – apenas o público estará disponível para eles:

 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' 

Resumindo, usando Factory é mais conveniente. Como a Factory não tem esses inconvenientes. Eu recomendaria usá-lo por padrão.

Mesmo quando dizem que todos os serviços e fábricas são singleton, eu não concordo 100% com isso. Eu diria que as fábricas não são singletons e este é o ponto da minha resposta. Eu realmente penso sobre o nome que define cada componente (Serviço / Fábrica), quero dizer:

Uma fábrica, porque não é um singleton, você pode criar quantas quiser quando for injetar, de modo que funcione como uma fábrica de objects. Você pode criar uma fábrica de uma entidade do seu domínio e trabalhar mais confortavelmente com esses objects, que poderiam ser como um object do seu modelo. Quando você recupera vários objects, você pode mapeá-los nesses objects e ele pode agir como uma outra camada entre o DDBB e o modelo AngularJs. Você pode adicionar methods aos objects para orientar os objects um pouco mais em seu aplicativo AngularJs.

Enquanto isso, um serviço é um singleton, então só podemos criar 1 de um tipo, talvez não criar, mas temos apenas 1 instância quando injetamos em um controlador, portanto, um serviço fornece mais como um serviço comum (rest chamadas, funcionalidade ..) aos controladores.

Conceitualmente, você pode pensar como os serviços fornecem um serviço, as fábricas podem criar várias instâncias (objects) de uma class

Serviços

Sintaxe : module.service (‘serviceName’, function); Resultado : Ao declarar serviceName como um argumento injetável, você receberá a referência da function real passada para module.service.

Uso : Pode ser útil para compartilhar funções de utilidade que são úteis para invocar simplesmente anexando () à referência de function injetada. Também pode ser executado com injectedArg.call (this) ou similar.

Fábricas

Sintaxe : module.factory (‘factoryName’, function);

Resultado : Ao declarar factoryName como um argumento injetável, você receberá o valor retornado, invocando a referência de function passada para module.factory.

Uso : Pode ser útil para retornar uma function de ‘class’ que pode então ser nova para criar instâncias.

Provedores

Sintaxe : module.provider (‘providerName’, function);

Resultado : Ao declarar providerName como um argumento injetável, você receberá o valor retornado, invocando o método $ get da referência de function passada para module.provider.

Uso : Pode ser útil para retornar uma function de ‘class’ que pode então ser nova para criar instâncias, mas isso requer algum tipo de configuração antes de ser injetado. Talvez seja útil para classs que são reutilizáveis ​​em projetos? Ainda meio nebuloso com isso.

Pode usar do jeito que você quiser : se criar um object ou apenas acessar funções de ambos


Você pode criar um novo object de serviço

 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 :

  • serviço por padrão retorna o object e não a function construtora.
  • Então é por isso que a function de construtor é definida para a propriedade this.model.
  • Devido a este serviço irá retornar o object, mas mas dentro desse object será a function construtora que será usada para criar um novo object;

Você pode criar um novo object 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 :

  • factory por padrão retorna a function construtora e não o object.
  • Então é por isso que um novo object pode ser criado com a function de construtor.

Criar serviço para acessar apenas funções simples

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

Crie uma fábrica para acessar apenas funções 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() }) 

Conclusão:

  • você pode usar tanto a maneira como deseja criar um novo object ou apenas acessar funções simples
  • Não haverá nenhum impacto no desempenho, usando um sobre o outro
  • Ambos são objects singleton e apenas uma instância é criada por aplicativo.
  • Sendo apenas uma instância em todo lugar aonde sua referência é passada.
  • Na fábrica de documentação angular é chamado de serviço e também o serviço é chamado de serviço .