Confuso sobre Serviço x Fábrica


618

Pelo que entendi, quando dentro de uma fábrica eu retorno um objeto que é injetado em um controlador. Quando estou dentro de um serviço, estou lidando com o objeto usando thise não retornando nada.

Eu assumi que um serviço sempre foi um singleton e que um novo objeto de fábrica é injetado em todos os controladores. No entanto, como se vê, um objeto de fábrica também é um singleton?

Código de exemplo para demonstrar:

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

Ao mudar user.firstem ACtrlverifica-se que user.firstem BCtrltambém é alterado, por exemplo, Useré um singleton?

Minha suposição era que uma nova instância foi injetada em um controlador com uma fábrica?


4
Ao lado de "module.service" e "module.factory", existem mais duas maneiras de criar serviços no AngularJS. Para mais informações cheque por correio blog: " Como criar serviços (únicas) AngularJS em 4 maneiras diferentes "
Emil van Galen

Respostas:


600

Todos os serviços angulares são singletons :

Documentos (consulte Serviços como singletons ): https://docs.angularjs.org/guide/services

Por fim, é importante perceber que todos os serviços Angular são singletons de aplicativos. Isso significa que há apenas uma instância de um determinado serviço por injetor.

Basicamente, a diferença entre o serviço e a fábrica é a seguinte:

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

Confira esta apresentação sobre $ deliver: http://slides.wesalvaro.com/20121113/#/

Esses slides foram usados ​​em um dos encontros do AngularJs: http://blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html


13
Consulte também stackoverflow.com/questions/15666048/…, que discute as diferenças entre serviço, fábrica e fornecimento.
Mark Rajcok

31
O documento oficial indiretamente [sic! não é claro o suficiente] implica que, mesmo se você definir o serviço com a fábrica, ele será criado apenas uma vez. Em outras palavras, NÃO é criado novamente como por referência (ponto de injeção) - como você o chamar. Ambas as formas resultam em uma instância única por injetor.
Honzajde

3
Você diz "serviço é apenas uma função construtora que será chamada com 'novo'", mas acho que isso é enganoso. Não acho que seja chamado de novo nos bastidores, acho que o desenvolvedor é responsável por chamá new-lo.
precisa saber é o seguinte

5
@nfiniteloop, verifique o código-fonte próximo à linha 3574. As fábricas são o método $ get de um provedor e os serviços geram fábricas usando um método que chama $ injector.instantiate na função fornecida, que então chama new. ( Veja Documentos )
citizenslave

14
Fiquei com a impressão de que um serviço era tão único que você usava, obtendo uma referência a ele. E que uma fábrica era um singleton que retornava um novo objeto a cada vez. Ou seja, um serviço forneceria um "carro" e tudo no seu projeto usaria esse carro. Enquanto uma fábrica lhe daria um carro novo cada vez que você a invocasse. Um era um singleton que retornou um singleton e um era um singleton que retornou um objeto. Alguém pode explicar? Chamar tudo de singleton não ajuda, pois pode se referir a várias coisas.
user2483724

380

Para mim, a revelação veio quando percebi que todos eles funcionam da mesma maneira: executando algo uma vez , armazenando o valor que recebem e depois tossindo esse mesmo valor armazenado quando referenciado por meio da Injeção de Dependência.

Digamos que temos:

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

A diferença entre os três é que:

  1. aO valor armazenado de vem da execução fn, em outras palavras:fn()
  2. bO valor armazenado de vem de newing fn, em outras palavras:new fn()
  3. cO valor armazenado é obtido primeiro pela obtenção de uma instância newing fne, em seguida, pela execução de um $getmétodo da instância

o que significa que há algo como um objeto de cache dentro do angular, cujo valor de cada injeção é atribuído apenas uma vez, quando foram injetados pela primeira vez e onde:

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

É por isso que usamos thisem serviços e definimos um this.$getem provedores.

Espero que isto ajude.


54
finalmente, uma explicação sensata. Angular é louco e tão ruim que dói.
Osíris

8
Essa deve ser a resposta aceita, pois na verdade responde à pergunta POR QUE fábricas, serviços e provedores retornam valores singleton. As outras respostas explicam a diferença entre fábricas, serviços e fornecedores, mas nunca abordam o aspecto singleton.
Wmock 25/09/2015

3
Eu gosto disso ... Quando leio as mil frases de outro blogueiro ... só consigo entender a fábrica. Mas eu li isso ... eu entendo tudo 3.
tsohtan

@osiris eu concordo. Eu não gosto disso Parece tão assustadoramente acoplado que faz meus dentes rangerem.
Thomas

2
então você deve fornecer uma implementação de $ get ao usar provedores?
Victor

95

exemplo ao vivo

exemplo "olá mundo"

com 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

Também existe uma maneira de retornar uma função construtora para que você possa retornar classes renováveis em fábricas, como este:

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

Então você pode fazer isso em um controlador, que usa MyObjectWithParam:

var obj = new MyObjectWithParam("hello"),

Veja aqui o exemplo completo:
http://plnkr.co/edit/GKnhIN?p=preview

E aqui as páginas do grupo do Google, onde foram discutidas:
https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ


Estou tendo problemas com a minificação usando seu exemplo. Você sabe como eu devo anotar isso?
Pål

2
Sim, existe uma notação reduzida para Angular. Deve ser algo como isto: App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); Leia mais sobre isso aqui: docs.angularjs.org/tutorial/step_05
JustGoscha

4
por que você quer fazer isso, se você pode usar .service?
Flup

eu tive o mesmo pensamento @ flup. @justgoscha, existe algum benefício ( percebido? ) de usar .factoryem oposição a .service?
Xandercoded

5
Eu acho que porque um serviço é um singleton . O que eu construí aqui é basicamente uma classe que é renovável. Então você pode ter algo como uma fábrica de serviço de carro e, em seguida, fazer new Car('BMW')e new Car('Ford')e eles não compartilham as mesmas variáveis e tudo.
JustGoscha

51

Aqui estão as principais diferenças:

Serviços

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

Resultado: ao declarar serviceName como um argumento injetável, você receberá a instância de uma 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', function );

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.

Verifique também a documentação do AngularJS e uma pergunta semelhante sobre o stackoverflow confusa sobre serviço x fábrica .

Aqui está um exemplo usando serviços e fábrica . Leia mais sobre o serviço AngularJS x fábrica .


6
Isso faz sentido para mim. A fábrica retorna o modelo para a criação de novos objetos.

27

Somando-se à primeira resposta, acho que .service () é para pessoas que escreveram seu código em um estilo mais orientado a objetos (C # / Java) (usando essa palavra-chave e instanciando o objeto por meio da função prototype / Constructor).

O Factory é para desenvolvedores que escrevem código mais natural ao estilo de codificação javascript / funcional.

Veja o código-fonte do método .service e .factory no angular.js - todos eles internamente chamam o método do provedor:

  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

Muito simplesmente:

.service - a função registrada será invocada como construtor (também conhecido como 'newed')

.factory - a função registrada será chamada como uma função simples

Ambos são invocados uma vez, resultando em um objeto singleton que é injetado em outros componentes do seu aplicativo.


6
sim. não vamos fazer as coisas mais complicadas do que realmente são
FLUP

20

Todos os provedores funcionam da mesma maneira. Os diferentes métodos service, factory, providerapenas deixá-lo fazer a mesma coisa em menos código.

PS Há também valuee constant.

Cada caso especial ao longo da cadeia, começando com providere terminando com, valuetem uma limitação adicional. Portanto, para decidir entre eles, você deve se perguntar o que permite realizar o que deseja com menos código.

Aqui está uma imagem que mostra o que quero dizer:

insira a descrição da imagem aqui

Você pode obter um guia de detalhamento e referência no post em que obtive esta imagem:

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


Diz-se que os serviços são singleton, mas como é que ele é singleton, se uma nova instância está sendo criada cada vez que eu injeto?
Ankur Marwaha

1
@AnkurMarwaha Uma nova instância não é criada a cada vez, é criada apenas uma vez e armazenada em cache pelo AngularJS. Isso é verdade se você estiver usando um fornecedor, fábrica, serviço etc. Você pode confirmar isso usando console.log()e injetando em vários controladores.
Luis Perez

Luis, seu comentário entra em conflito com a resposta aceita, como diz - Por último, é importante perceber que todos os serviços Angular são singletons de aplicativos. Isso significa que há apenas uma instância de um determinado serviço por injetor.
Ankur Marwaha

@AnkurMarwaha talvez eu esteja entendendo algo errado. Você citou "é importante perceber que todos os serviços Angular são singletons de aplicativos" - o fato de serem singletons significa que são criados apenas uma vez. Foi o que eu disse "Uma nova instância não é criada a cada vez, é criada apenas uma vez e armazenada em cache ...". Você pode apontar com mais detalhes onde você vê o conflito?
Luis Perez

1
Ah, eu vejo a confusão. O "injetor" é um objeto angular. É responsável por fazer a "injeção". Por exemplo, quando o controlador é executado pela primeira vez, o "injetor" analisa os parâmetros e injeta cada um. Existe apenas um "injetor" para todo o aplicativo. Uma vez que o injetor cria uma fábrica ou serviço específico, ele mantém uma instância e a reutiliza - daí o singleton. Portanto, existe apenas um injetor por aplicativo e apenas uma instância de um determinado serviço por injetor. A maioria das aplicações angulares só tem um aplicativo, portanto, um injetor, portanto, uma instância de qualquer serviço, controlador, etc.
Luis Perez

13

Aqui estão mais alguns exemplos de serviços versus fábricas que podem ser úteis para ver a diferença entre eles. Basicamente, um serviço tem "novo ..." chamado, ele já é instanciado. Uma fábrica não é instanciada automaticamente.

Exemplos básicos

Retornar um objeto de classe que possui um único método

Aqui está um serviço que possui um único método:

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

Aqui está uma fábrica que retorna um objeto com um método:

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

Retornar um valor

Uma fábrica que retorna uma lista de números:

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

console.log(NumberListFactory);

Um serviço que retorna uma lista de números:

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

console.log(NumberLister.numbers);

A saída em ambos os casos é a mesma, a lista de números.

Exemplos avançados

Variáveis ​​de "classe" usando fábricas

Neste exemplo, definimos um CounterFactory, ele aumenta ou diminui um contador e você pode obter a contagem atual ou quantos objetos CounterFactory foram criados:

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 o CounterFactorypara criar vários contadores. Podemos acessar a variável de classe para ver quantos contadores foram criados:

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

A saída deste código é:

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

é um exemplo útil, number_of_counter_factories é como um meta atributo da classe CounterFactory, certo ?, Entendo que este exemplo é replicável em um serviço (diga-me se estou errado), qual seria a diferença semântica nesse caso?
geoom 9/07/2015

Exemplo útil! Portanto, isso basicamente significa que em uma fábrica você pode ter uma camada extra de abstração que não entraria em um serviço. O que quer que seja retornado, porém, uma nova instância será retornada sempre que 'novo' for usado. Quaisquer variáveis ​​que não forem declaradas dentro do bloco de retorno serão únicas. Eu entendi direito?
Swanidhi 26/09

@Swanidhi basicamente sim, você pode declarar variáveis ​​que são singletons na fábrica. Por isso os chamei de variáveis ​​de "classe".

13

“Fábrica” e “Serviço” são diferentes maneiras de executar DI (injeção de dependência) em angular.

Então, quando definimos o DI usando "service", como mostrado no código abaixo. Isso cria uma nova instância GLOBAL do objeto "Logger" e a injeta na função.

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

Quando você define o DI usando uma "fábrica", ele não cria uma instância. Apenas passa o método e, posteriormente, o consumidor internamente precisa fazer chamadas para a fábrica em busca de instâncias de objetos.

app.factory("Customerfactory", CreateCustomer);

Abaixo está uma imagem simples que mostra visualmente como o processo de DI para "Serviço" é diferente de "Fábrica".

insira a descrição da imagem aqui

Fábrica deve ser usada Quando queremos criar diferentes tipos de objetos, dependendo dos cenários. Por exemplo, dependendo do cenário, queremos criar um objeto "Cliente" simples, ou "Cliente" com o objeto "Endereço" ou "Cliente" com o objeto "Telefone". Aqui está uma explicação detalhada deste parágrafo

O serviço deve ser usado Quando temos utilidade ou funções compartilhadas a serem injetadas, como Utility, Logger, Error handler etc.


Todas as respostas que eu vi sobre essa questão e outras similares estão especificando a diferença de mecânica e sintaxe. Esta resposta fornece uma verdadeira razão pela qual você selecionaria uma sobre a outra. É uma questão de semântica e, olhando o nome, serviço ou fábrica, comunica seu propósito e como eles são usados.
31516 Joe Mayo

8

Estilo de serviço : ( provavelmente o mais simples ) retorna a função real: Útil para compartilhar funções utilitárias que são úteis para chamar, simplesmente anexando () à referência da função injetada.

Um serviço no AngularJS é um objeto JavaScript singleton que contém um conjunto de funções

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 : ( mais envolvido, mas mais sofisticado ) retorna o valor de retorno da função: instancia um objeto como new Object () em java.

Factory é uma função que cria valores. Quando um serviço, controlador etc. precisa de um valor injetado de uma fábrica, a fábrica cria o valor sob demanda. Uma vez criado, o valor é reutilizado para todos os serviços, controladores etc. que precisam dele injetado.

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 do provedor : ( versão configurável completa ) retorna a saída da função $ get da função: Configurável.

Os fornecedores no AngularJS são a forma mais flexível de fábrica que você pode criar. Você registra um provedor com um módulo, exatamente como em um serviço ou fábrica, exceto pelo uso da função provider ().

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

A diferença básica é que o provedor permite definir valores primitivos (não-objetos), matriz ou função de retorno de chamada na variável declarada de fábrica e, portanto, se você retornar um objeto, ele deverá ser explicitamente declarado e retornado.

Por outro lado, um serviço só pode ser usado para definir a variável declarada de serviço como um objeto, portanto, podemos evitar a criação explícita e o retorno dos objetos, enquanto, por outro lado, permite o uso da palavra - chave this .

Ou, em poucas palavras, " provedor é uma forma mais genérica, enquanto o serviço é limitado apenas a objetos".


2

Foi assim que entendi a diferença entre eles em termos de padrões de design:

Serviço : retorne um tipo que será renovado para criar um objeto desse tipo. Se a analogia Java for usada, o Serviço retornará uma definição de Classe Java .

Fábrica : retorna um objeto concreto que pode ser usado imediatamente. Na analogia Java, uma fábrica retorna um objeto Java .

A parte que muitas vezes confunde as pessoas (inclusive eu) é que, quando você injeta um Serviço ou uma Fábrica no seu código, elas podem ser usadas da mesma maneira, o que você obtém no seu código nos dois casos é um objeto concreto que você pode chamar imediatamente. O que significa que, no caso do Serviço, chamadas angulares "novas" na declaração de serviço em seu nome. Eu acho que esse é um conceito complicado.


1

Essa seria a melhor e curta resposta para entender o serviço versus fornecedor de fábrica

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

Aqui o que ben diz com uma demonstração http://jsbin.com/ohamub/1/edit?html,output

"Existem comentários no código que ilustram as principais diferenças, mas vou expandi-las um pouco aqui. Como observação, estou apenas tentando entender isso, então, se disser algo errado, entre em contato.

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. "Ben


1

Eu tive essa confusão por um tempo e estou tentando o meu melhor para fornecer uma explicação simples aqui. Espero que isso ajude!

angular .factorye angular .serviceambos são usados ​​para inicializar um serviço e trabalhar da mesma maneira.

A única diferença é como você deseja inicializar seu serviço.

Ambos são singletons


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


Fábrica

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

Se você deseja inicializar seu serviço a partir de uma função que possui um valor de retorno , use este factorymétodo.

por exemplo

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

app.factory('myService', myService);

Ao injetar este serviço (por exemplo, no seu controlador):

  • Angular chamará sua função (as myService()) para retornar o objeto
  • Singleton - chamado apenas uma vez, armazenado e passa o mesmo objeto.


Serviço

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

Se você deseja inicializar seu serviço a partir de uma função construtora (usando a thispalavra-chave), use este servicemétodo.

por exemplo

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

app.service('myService', myService);

Ao injetar este serviço (por exemplo, no seu controlador):

  • Angular fará com que newsua função (as new myService()) retorne o objeto
  • Singleton - chamado apenas uma vez, armazenado e passa o mesmo objeto.


NOTA: Se você usar factorycom <constructor function>ou servicecom <function with a return value>, ele não funcionará.


Exemplos - DEMOs


1

Foi isso que me ajudou a entender a diferença, graças a um post de Pascal Precht.

Um serviço é um método em um módulo que leva um nome e uma função que define o serviço. Você pode injetar e usar esse serviço específico em outros componentes, como controladores, diretivas e filtros. Uma fábrica é um método em um módulo e também leva um nome e uma função, que define a fábrica. Também podemos injetar e usar da mesma maneira que fizemos com o serviço.

Os objetos criados com o novo usam o valor da propriedade prototype de sua função construtora como protótipo; portanto, encontrei o código Angular que chama Object.create (), que acredito ser a função construtora de serviço quando é instanciada. No entanto, uma função de fábrica é realmente apenas uma função que é chamada, e é por isso que precisamos retornar um objeto literal para a fábrica.

Aqui está o código angular 1.5 que encontrei para a 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-fonte angular para a função factory ():

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

Ele pega o nome e a função de fábrica que é passada e retorna um provedor com o mesmo nome, que possui um método $ get, que é a nossa função de fábrica. Sempre que você solicita ao injetor uma dependência específica, ele basicamente solicita ao provedor correspondente uma instância desse serviço, chamando o método $ get (). É por isso que $ get () é necessário ao criar provedores.

Aqui está o código angular 1.5 para serviço.

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

Acontece que quando chamamos service (), na verdade, chama factory ()! No entanto, ele não apenas passa nossa função de construtor de serviço para a fábrica como está. Ele também passa uma função que solicita ao injetor que instancia um objeto pelo construtor especificado.

Em outras palavras, se injetarmos o MyService em algum lugar, o que acontece no código é:

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

Para reajustá-lo novamente, um serviço chama uma fábrica, que é um método $ get () no provedor correspondente. Além disso, $ injector.instantiate () é o método que finalmente chama Object.create () com a função construtora. É por isso que usamos "isso" nos serviços.

Para o ES5, não importa qual seja o uso: service () ou factory (), é sempre uma fábrica chamada que cria um provedor para o nosso serviço.

Você pode fazer exatamente a mesma coisa com os serviços também. Um serviço é uma função construtora, no entanto, que não nos impede de retornar literais de objetos. Assim, podemos pegar nosso código de serviço e escrevê-lo de uma maneira que basicamente faz exatamente a mesma coisa que nossa fábrica ou, em outras palavras, você pode escrever um serviço como fábrica para retornar um objeto.

Por que a maioria das pessoas recomenda usar fábricas em vez de serviços? Esta é a melhor resposta que eu vi que vem do livro de Pawel Kozlowski: Mastering Web Application Development with AngularJS.

O método de fábrica é a maneira mais comum de colocar objetos no sistema de injeção de dependência do 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 variáveis ​​"privadas". Isso é muito útil, pois podemos ocultar os detalhes da implementação de um determinado serviço ".


1
  • Com a fábrica, você realmente cria um objeto dentro da fábrica e o devolve.
  • Com o serviço, você apenas tem uma função padrão que usa a thispalavra-chave para definir a função.
  • Com o provedor, existe um que $getvocê define e pode ser usado para obter o objeto que retorna os dados.

1

Existem três maneiras de lidar com a lógica de negócios no AngularJS: ( Inspirado no curso Coursera AngularJS de Yaakov ):

  1. Serviço
  2. Fábrica
  3. Fornecedor

Aqui vamos falar apenas sobre Serviço x Fábrica

SERVIÇO :

Sintaxe:

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>

Os principais recursos do serviço:

  1. Instanciado preguiçosamente : se o serviço não for injetado, ele nunca será instanciado. Então, para usá-lo, você precisará injetá-lo em um módulo.

  2. Singleton : se for injetado em vários módulos, todos terão acesso a apenas uma instância específica. Por isso, é muito conveniente compartilhar dados entre diferentes controladores.

FÁBRICA

Agora vamos falar sobre a fábrica no AngularJS

Primeiro, vamos dar uma olhada na sintaxe :

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

Agora, usando os dois acima no controlador:

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

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

Características da fábrica:

  1. Esses tipos de serviços seguem o padrão de design da fábrica . A fábrica pode ser pensada como um local central que cria novos objetos ou métodos.

  2. Isso não produz apenas singleton, mas também serviços personalizáveis.

  3. O .service()método é uma fábrica que sempre produz o mesmo tipo de serviço, que é um singleton. Não há uma maneira fácil de configurar seu comportamento. Esse .service()método é geralmente usado como um atalho para algo que não requer nenhuma configuração.



0

Você pode entender a diferença com esta analogia - considere a diferença entre uma função normal que retornará algum valor e a função construtora que será instanciada usando a nova palavra-chave. um objeto), ao passo que criar serviço é como criar função construtora (classe OO), da qual podemos criar instância usando a nova palavra-chave. A única coisa a notar é que, quando usamos o método Service para criar serviços, ele automaticamente cria uma instância usando o mecanismo de injeção de dependência suportado pelo AngularJS

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.