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

296

Por favor, tenha paciência comigo aqui. 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 na fábrica.

Pelo que sei, 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 invés do serviço. Eles até se referem ao "serviço" quando usam a fábrica, o 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 se passa nos bastidores? Diferenças de desempenho / memória?

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

Atualização: Com a resposta de Thomas, parece implicar que o serviço é mais simples e a fábrica é mais complexa com métodos privados. Por isso, 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()
    ];
}
user1941747
fonte
é claro que o serviço suporta privado, mas se você ler corretamente minha postagem, é puramente estilo de código: também podemos aproveitar um novo escopo lexical para simular variáveis ​​"privadas". É "SIMULADO"
Thomas Pons
Acho essa discussão muito útil stackoverflow.com/questions/15666048/...
Anand Gupta
2
algumas boas respostas aqui também.
Mistalis

Respostas:

280

Explicação

Você tem coisas diferentes aqui:

Primeiro:

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

ref: angular.service vs angular.factory

Segundo:

Lembre-se de que todos os provedores do AngularJS (valor, constante, serviços, fábricas) são singletons!

Terceiro:

Usar um ou outro (serviço ou fábrica) é sobre o estilo do código. Mas, a maneira comum no AngularJS é usar a fábrica .

Por quê ?

Como "O método de fábrica é a maneira mais comum de inserir objetos 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 tirar proveito de um novo escopo lexical para simular" private "variable. 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 utilitárias que são úteis para chamar, simplesmente anexando ()à referência da função injetada. Também pode ser executado com injectedArg.call(this)ou similar.

Fábrica: pode ser útil para retornar uma função 'class' que pode ser nova para criar instâncias.

Portanto, use uma fábrica quando 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, use service .

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

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


ATUALIZAÇÃO:

Excelente publicação aqui: http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html

"Se você deseja que sua função seja chamada como uma função normal , use factory . Se você deseja que sua função seja instanciada com o novo operador, use o serviço. Se você não souber a diferença, use factory".


ATUALIZAÇÃO:

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

E a partir desta página:

"O Factory e o Service são as receitas mais usadas. A única diferença entre elas é que a receita do Service funciona melhor para objetos de tipo personalizado, enquanto o Factory pode produzir primitivas e funções JavaScript."

Thomas Pons
fonte
7
Re Primeiro: Li isso em toda parte, mas não entendo as implicações práticas disso. Eu acho que a partir de sua resposta, não há diferença prática "na maior parte"? Obrigado pelo livro ref embora!
user1941747
É simples, se o seu serviço é realmente complexo e necessita de métodos particulares e objetos usam uma fábrica
Thomas Pons
1
Notei que você adicionou "Se você deseja retornar uma instância de um serviço, use service". Minha pergunta de acompanhamento seria QUANDO você gostaria de retornar uma instância de um serviço? Estou tentando encontrar um caso de uso específico aqui.
User1941747
12
"Como as fábricas são funções regulares, também podemos tirar proveito de um novo escopo lexical para simular variáveis" privadas "". - isso não é específica para as fábricas, você pode fazer o mesmo com os serviços ..
pootzko
Parece que a equipe do Google prefere o serviço à fábrica, isso torna as coisas ainda mais confusas! google-styleguide.googlecode.com/svn/trunk/…
xzhang
111

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

Diretamente de 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. Enquanto o CarFactory retorna uma função para que você possa fazer new CarFactoryno seu controlador, passando vários cilindros específicos para esse carro. Você não pode fazer isso new CarServiceporque o CarService é um objeto, não uma função.

A razão pela qual as fábricas não funcionam assim:

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

E retornar automaticamente uma função para você instanciar, é porque então você não pode fazer isso (adicione itens 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 de seu blog é muito boa:

Em conclusão,

---------------------------------------------------  
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------  
| Factory | Yes      | Yes          | No          |
---------------------------------------------------  
| Service | Yes      | No           | No          |
---------------------------------------------------  
| Provider| Yes      | Yes          | Yes         |       
---------------------------------------------------  
  1. Use Service quando precisar apenas de um objeto simples, como um Hash, por exemplo {foo; 1, bar: 2} É fácil de codificar, mas você não pode instancia-lo.

  2. Use o Factory quando precisar instanciar um objeto, ou seja, novo Cliente (), novo Comentário (), 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ê descobrir que está devolvendo um objeto na fábrica, provavelmente deverá usar o serviço.

Não faça isso:

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

Use o serviço:

app.service('CarService', function() {
    this.numCylinder = 4;
});
Jonathan.
fonte
11
é muito útil para mim. +1 para a tabela de comparação
Vu Anh
5
se você definir a função de serviço com um numCylinder parâmetro, então ele vai ter a mesma flexibilidade que o método de fábrica
Ovi
vá e leia o blog do post e perca seu tempo tentando descobrir angular, se você souber javascript depois de ler este post, entenderá totalmente a diferença entre isso.
Ncubica
4
Muito surpreso ! Você está consultando um blog aqui e ambos estão dizendo algo completamente oposto. Você diz: Fábrica - Instantiable - Sim O blog diz: Fábrica - Instantiable - Não
Devesh M
1
Eu concordo com @Devesh. Eu acho que você tem os instanciados misturados. Na postagem do blog: "Somente na fábrica, você não pode conseguir isso porque a fábrica não pode ser instanciada".
Matt
20

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

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

Desde que o provedor faça o que puder, você poderá usá-lo ainda mais na cadeia, o que resultaria na criação de menos código. Se não conseguir o que você deseja, você pode subir a cadeia e precisará 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, um valor etc.

Fornecedores, fábricas, serviços, etc, do AngularJS, são a mesma coisa
(fonte: simplygoodcode.com )

Para obter mais detalhes e exemplos da postagem do blog em que obtive a imagem, acesse: http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/

Luis Perez
fonte
8

Tanto a fábrica quanto o serviço resultam em objetos singleton que podem ser configurados pelos fornecedores e injetados nos controladores e executar blocos. Do ponto de vista do injetado, não há absolutamente nenhuma diferença se o objeto 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 da função construtora ("classe"), vá para o serviço. Observe que ambos os estilos oferecem suporte a membros particulares.

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

Steve Lang
fonte
Você poderia fornecer um exemplo do que você quer dizer com fornecer parâmetros diferentes ao construtor em um bloco de configuração? Como você fornece parâmetros se é apenas um serviço ou fábrica. O que você quer dizer com "em conjunto com um provedor"? Ser capaz de configurá-lo me faz pensar que muitos dos meus objetos devem ser provedores versus fábricas ou serviços.
timbrown
2

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 é sua conveniência em lidar com membros públicos / privados. O serviço seria mais desajeitado a esse respeito. Ao codificar um Serviço, você tende a tornar públicos os membros do seu objeto por meio da palavra-chave "this" e, de repente, pode descobrir que esses membros públicos não são visíveis a métodos privados (por exemplo, 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ê, portanto, a instância que Angular 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'  

Porém, com uma constante de serviço grande, isso tornaria o código pouco 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, usar o Factory é mais conveniente. Como o Factory não possui essas desvantagens. Eu recomendaria usá-lo por padrão.

Andrew Krook
fonte
Esta resposta tem vários problemas. Primeiro, este post demonstra o conceito de escopo lexical do Javascript, e não como o serviço AngularJS funciona. Segundo, o contexto da chamada myapp.service(...)está completamente ausente. Onde new Service()deve ser chamado, na função de serviço ou no local onde o Serviço é injetado. A terceira listagem simplesmente não é possível no contexto de myapp.service ('Service', function() {...}).
Lanoxx 02/03
2

Mesmo quando dizem que todos os serviços e fábricas são únicos, não concordo 100% com isso. Eu diria que as fábricas não são singletons e esse é o ponto da minha resposta. Eu realmente pensaria no 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 injeta, para que funcione como uma fábrica de objetos. Você pode criar uma fábrica de uma entidade do seu domínio e trabalhar mais confortavelmente com esses objetos, que podem ser como um objeto do seu modelo. Quando você recupera vários objetos, é possível mapeá-los nesses objetos e ele pode agir como uma outra camada entre o DDBB e o modelo AngularJs. Você pode adicionar métodos aos objetos para orientar os objetos um pouco mais no aplicativo AngularJs.

Enquanto isso, um serviço é um singleton, portanto, podemos criar apenas um de um tipo, talvez não, mas temos apenas uma instância quando injetamos em um controlador, portanto, um serviço se parece mais com um serviço comum (chamadas de descanso, funcionalidade ..) para os controladores.

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

francisco J Jimenez Garcia
fonte
0

Serviços

Sintaxe : module.service ('serviceName', função); Resultado : ao declarar serviceName como um argumento injetável, você receberá a referência real da função passada para module.service.

Uso : Pode ser útil para compartilhar funções utilitárias que são úteis para chamar, simplesmente anexando () à referência da função injetada. Também pode ser executado com injectedArg.call (this) ou similar.

Fábricas

Sintaxe : module.factory ('factoryName', função);

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

Uso : Pode ser útil para retornar uma função 'class' que pode ser renovada para criar instâncias.

Fornecedores

Sintaxe : module.provider ('providerName', função);

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

Uso : Pode ser útil para retornar uma função de 'classe' que pode ser nova para criar instâncias, mas que requer algum tipo de configuração antes de ser injetada. Talvez útil para classes reutilizáveis ​​em projetos? Ainda meio nebuloso neste.

Nishant Upadhyay
fonte
0

Pode usar da maneira que você deseja : criar objeto ou apenas acessar funções de ambos


Você pode criar um novo objeto 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 objeto e não função construtora.
  • É por isso que a função construtora é configurada para a propriedade this.model.
  • Devido a este serviço, o objeto retornará, mas mas dentro desse objeto haverá a função construtora que será usada para criar um novo objeto;

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

  • factory por padrão retorna a função do construtor e não o objeto.
  • É por isso que um novo objeto pode ser criado com a função construtora.

Crie um serviço apenas para acessar 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 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 da maneira que desejar, seja para criar um novo objeto ou apenas para acessar funções simples
  • Não haverá nenhum impacto no desempenho, usando um sobre o outro
  • Ambos são objetos singleton e apenas uma instância é criada por aplicativo.
  • Sendo apenas uma instância em todo lugar em que sua referência é passada.
  • Na documentação angular, a fábrica é chamada de serviço e também o serviço é chamado de serviço .
vijay
fonte
0

Fábrica e Serviço são o método mais usado. A única diferença entre eles é que o método Service funciona melhor para objetos que precisam de hierarquia de herança, enquanto o Factory pode produzir primitivas e funções JavaScript.

A função Provedor é o método principal e todos os outros são apenas açúcar sintático. Você precisa apenas se estiver criando um código reutilizável que precise de configuração global.

Existem cinco métodos para criar serviços: Valor, Fábrica, Serviço, Fornecedor e Constante. Você pode aprender mais sobre isso aqui serviço angular . Este artigo explica todos esses métodos com exemplos práticos de demonstração.

.

user3114005
fonte