对服务vs工厂感到困惑
据我了解,当在工厂内部时,我返回一个被注入控制器的对象。 当在一个服务中,我正在处理这个对象,而不是返回任何东西。
我假设一个服务总是单身 ,并且每个控制器都注入一个新的工厂对象 。 然而,事实证明,一个工厂对象也是一个单身?
示例代码来演示:
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; });
当在ACtrl
改变user.first
时,事实证明, user.first
中的BCtrl
也被改变了,例如User
是一个singleton?
我的假设是一个新的实例被注入一个控制器与工厂?
所有的角度服务是单身人士 :
文档(请参阅服务为单例 ): https : //docs.angularjs.org/guide/services
最后,认识到所有的Angular服务都是应用单例是很重要的。 这意味着每个喷油器只有一个给定服务的实例。
基本上服务和工厂的区别如下:
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 + "!"; } } });
查看关于$ provide的演示文稿: http : //slides.wesalvaro.com/20121113/#/
这些幻灯片用于AngularJs聚会中的一个: http : //blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html
对我来说,当我意识到它们都以相同的方式工作时,启示就来了:通过运行一次 ,存储它们得到的值,然后通过依赖注入来引用相同的存储值 。
假设我们有:
app.factory('a', fn); app.service('b', fn); app.provider('c', fn);
三者的区别在于:
-
a
的存储值来自运行fn
,换句话说:fn()
-
b
的存储值来自new
fn
,换句话说:new fn()
-
c
的存储值来自首先通过new
fn
获取实例,然后运行实例的$get
方法
这意味着,在角度内部有一个类似缓存对象的东西,每次注入的值只在第一次被注入时被赋值一次,以及其中:
cache.a = fn() cache.b = new fn() cache.c = (new fn()).$get()
这就是为什么我们在服务中使用this
,并定义一个this.$get
in providers。
希望这可以帮助。
活的例子
“你好世界”的例子
与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()]; }
还有一种方法可以返回一个构造函数,这样你可以在工厂中返回新类,如下所示:
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 }); }; });
所以你可以在一个使用MyObjectWithParam的控制器中做到这一点:
var obj = new MyObjectWithParam("hello"),
在这里看到完整的例子:
http://plnkr.co/edit/GKnhIN?p=preview
在这里的谷歌组页面,在那里讨论:
https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ
以下是主要区别:
服务
语法: module.service( 'serviceName', function );
结果:当将serviceName声明为注入参数时,将为您提供传递给module.service
的函数的实例 。
用法:对于通过简单追加()到注入的函数引用来调用有用的共享实用程序函数可能很有用。 也可以运行injectedArg.call( this )
或类似的。
工厂
语法: module.factory( 'factoryName', function );
结果:将factoryName声明为注入参数时,将提供通过调用传递给module.factory
的函数引用返回的值 。
用法:可以用于返回一个“类”函数,然后可以创建新的实例。
同时检查关于服务vs工厂的关于stackoverflow的AngularJS文档和类似的问题。
这里是使用服务和工厂的例子 。 阅读更多关于AngularJS服务与工厂 。
添加到第一个答案,我认为.service()是为更多的面向对象的风格(C#/ Java)(使用此关键字和通过原型/构造函数实例化对象)编写代码的人。
工厂是为开发人员编写的代码更自然的JavaScript /功能风格的编码。
看看angular.js中.service和.factory方法的源代码 – 在内部它们都调用提供者方法:
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); }]); }
非常简单:
.service – 注册函数将作为构造函数被调用(又名'newed')
.factory – 注册函数将作为一个简单的函数被调用
两者都被调用一次,导致一个单例对象被注入到应用程序的其他组件中。
所有提供者的工作方式相同。 不同的方法service
, factory
, provider
只是让你用较少的代码完成同样的事情。
PS还有value
和constant
。
从provider
开始,以value
结束的每个特殊情况都有一个额外的限制。 因此,要决定他们之间,你必须问自己哪个让你用更少的代码完成你想要的。
这里是一张图片,显示你的意思:
你可以在博客文章中的细分和参考指南我从这个图像:
以下是一些服务与工厂的例子,可能有助于了解它们之间的区别。 基本上,一个服务有“新的”,它已经实例化。 工厂不会自动实例化。
基本例子
返回一个具有单一方法的类对象
这是一个单一方法的服务:
angular.service('Hello', function () { this.sayHello = function () { /* ... */ }; });
这是一个工厂,返回一个方法的对象:
angular.factory('ClassFactory', function () { return { sayHello: function () { /* ... */ } }; });
返回一个值
返回数字列表的工厂:
angular.factory('NumberListFactory', function () { return [1, 2, 3, 4, 5]; }); console.log(NumberListFactory);
返回数字列表的服务:
angular.service('NumberLister', function () { this.numbers = [1, 2, 3, 4, 5]; }); console.log(NumberLister.numbers);
两种情况下的输出都是相同的,即数字列表。
高级示例
使用工厂的“类”变量
在这个例子中,我们定义一个CounterFactory,它增加或减少一个计数器,你可以得到当前的计数,或者得到多少个CounterFactory对象被创建:
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; }; } })
我们使用CounterFactory
来创建多个计数器。 我们可以访问类变量来查看创建了多少个计数器:
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());
这个代码的输出是:
people 0 people 1 counters 1 places 0 counters 2 counters 2
“工厂”和“服务”是角度进行DI(依赖注入)的不同方式。
所以当我们使用“service”来定义DI时,如下面的代码所示。 这将创建一个新的“记录器”对象的GLOBAL实例,并将其注入到函数中。
app.service("Logger", Logger); // Injects a global object
当使用“工厂”定义DI时,它不会创建实例。 它只是通过该方法,后来消费者内部必须调用工厂的对象实例。
app.factory("Customerfactory", CreateCustomer);
下面是一个简单的图像,可视化地显示“服务”的DI过程与“工厂”不同。
应该使用工厂当我们要根据情景创建不同类型的对象。 例如,根据情况,我们要创建一个简单的“客户”对象,或“客户”与“地址”对象或“客户”与“电话”对象。 这里是对这一段的详细解释
应该使用服务当我们有实用程序或共享功能注入像工具,记录器,错误处理等
服务风格:( 可能是最简单的一个 )返回实际的功能:用于共享实用程序功能,通过简单地追加()到注入的函数引用来调用。
AngularJS中的服务是一个包含一组函数的单例JavaScript对象
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(); });
工厂风格:( 更多的参与但更复杂 )返回函数的返回值:在java中实例化一个对象,如新的Object()。
工厂是一个创造价值的功能。 当服务,控制器等需要从工厂注入的价值时,工厂按需创建价值。 一旦创建,该值将被重用于需要注入的所有服务,控制器等。
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); });
提供者风格:( 完整的,可配置的版本 )返回函数的$ get函数的输出:可配置的。
AngularJS中的提供者是您可以创建的最灵活的工厂形式。 您可以像使用服务或工厂一样为模块注册一个提供者,除非使用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詹科夫
<!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>
基本的区别在于, 提供者允许将原始(非对象),数组或回调函数值设置为工厂声明变量,因此如果返回对象,则必须显式声明并返回该对象。
另一方面, 服务只能用于将服务声明变量设置为对象,因此可以避免显式创建和返回对象,另一方面允许使用this关键字。
或者简而言之,“ 提供者是一种更通用的形式,而服务仅限于对象”。
这就是我如何从设计模式上理解他们之间的差异:
服务 :返回一个类型,将会被创建一个类型的对象。 如果使用Java类比,Service将返回一个Java类定义 。
工厂 :返回可以立即使用的具体对象。 在Java中,类比工厂返回一个Java对象 。
经常让人们(包括我自己)困惑的部分是,当你在代码中注入一个Service或者一个Factory时,它们可以以同样的方式使用,在这两种情况下你在代码中得到的是一个可以立即调用的具体对象。 这意味着在服务的情况下,代表你的服务声明角度调用“新”。 我认为这是一个复杂的概念。
AngularJS服务与工厂
module.service( 'serviceName', function ); module.factory( 'factoryName', function );
将serviceName
声明为injectable
参数时,将为您提供该函数的一个实例。 换句话说,新的FunctionYouPassedToService()
。 这个对象实例成为AngularJS
注册并在需要时注入其他services / controllers
的服务对象。
将factoryName
声明为injectable
参数时,将提供通过调用传递给module.factory
的函数引用返回的值。
在下面的例子中,我们用两种不同的方式定义MyService
。 请注意在.service中如何使用this.methodname
创建服务方法。 在.factory中,我们创建了一个工厂对象并将其分配给它。
AngularJS .service
module.service('MyService', function() { this.method1 = function() { //.. } this.method2 = function() { //.. } });
AngularJS。工厂
module.factory('MyService', function() { var factory = {}; factory.method1 = function() { //.. } factory.method2 = function() { //.. } return factory; });
我们可以像这样定义一个服务:
app.service('MyService', function () { this.sayHello = function () { console.log('hello'); }; });
.service()
是我们模块上的一个方法,它接受一个名称和一个定义服务的函数。 非常直截了当。 一旦定义,我们可以在其他组件中注入和使用特定的服务,如控制器,指令和过滤器,如下所示:
现在和工厂一样:
app.factory('MyService', function () { return { sayHello: function () { console.log('hello'); } } });
同样, .factory()
是我们模块上的一个方法,它也需要一个名称和一个函数来定义工厂。 我们可以像使用服务一样注入和使用这个东西。 现在有什么区别?
那么,你可能会看到,而不是在工厂工作,我们正在返回一个对象文字。 这是为什么? 事实证明,一个服务是一个构造函数,而一个工厂则不是。 在这个Angular世界深处的某个地方,有这样的代码,当它被实例化时,这个代码会调用Object.create()和服务构造函数。 但是,工厂函数实际上只是一个被调用的函数,这就是为什么我们必须显式地返回一个对象。
这将是了解Service Vs Factory Vs Provider的最佳答案
来源 : https : //groups.google.com/forum/#! msg / angular/ 56sdORWEoqg / HuZsOsMvKv4J
这里是什么本与演示 http://jsbin.com/ohamub/1/edit?html,output说;
“代码中有一些注释说明了主要的区别,但是我会在这里稍微扩展一下,作为一个注释,我只是开始讨论这个问题,所以如果我说什么是错的,请告诉我。
服务
语法 :module.service('serviceName',function);
结果 :将serviceName声明为注入参数时,将提供传递给module.service的实际函数引用。
用法 :对于通过简单追加()到注入的函数引用来调用有用的共享实用程序函数可能很有用。 也可以运行injectArg.call(this)或类似的。
工厂
语法 :module.factory('factoryName',function);
结果 :将factoryName声明为注入参数时,将提供通过调用传递给module.factory的函数引用返回的值。
用法 :可以用于返回一个“类”函数,然后可以创建新的实例。
供应商
语法 :module.provider('providerName',function);
结果 :将providerName声明为注入参数时,将提供通过调用传递给module.provider的函数引用的$ get方法返回的值。
用法 :可以用于返回一个'class'函数,然后可以new'ed创建实例,但需要某种配置之前被注入。 对于可跨项目重用的类也许有用? 这个还是朦胧的。“本
我有一段时间有这个困惑,我正在尽力在这里提供一个简单的解释。 希望这会有所帮助!
angular .factory
和angular .service
都用于初始化一个服务,并以相同的方式工作。
唯一的区别是,你想如何初始化你的服务。
两者都是单身人士
var app = angular.module('app', []);
厂
app.factory( <service name>
, <function with a return value>
)
如果您想从具有返回值的函数初始化您的服务,则必须使用此factory
方法。
例如
function myService() { //return what you want var service = { myfunc: function (param) { /* do stuff */ } } return service; } app.factory('myService', myService);
注入此项服务时(例如向您的控制器):
- Angular会调用你的给定函数(如
myService()
)来返回对象 - Singleton – 只调用一次,存储并传递相同的对象。
服务
app.service( <service name>
, <constructor function>
)
如果您想从构造函数 (使用this
关键字)初始化您的服务,则必须使用此service
方法。
例如
function myService() { this.myfunc: function (param) { /* do stuff */ } } app.service('myService', myService);
注入此项服务时(例如向您的控制器):
- Angular将
new
的给定函数(如new myService()
)返回给对象 - Singleton – 只调用一次,存储并传递相同的对象。
注意:如果您使用<constructor function>
factory
或<function with a return value>
<constructor function>
service
,它将无法工作。
示例 – DEMO
- 角度服务vs工厂
- Angular Service vs Factory(含路线)
这是帮助我理解这种差异的原因,这要归功于Pascal Precht的博客文章。
服务是一个模块上的一个方法,它需要一个名称和一个定义服务的函数。 您可以在其他组件中注入和使用该特定服务,如控制器,指令和过滤器。 工厂是模块上的一个方法,它也需要一个名称和一个函数来定义工厂。 我们也可以像使用服务一样注入和使用。
用new创建的对象使用构造函数原型的属性值作为它的原型,所以我找到了调用Object.create()的Angular代码,我相信它是实例化时的服务构造函数。 However, a factory function is really just a function that gets called, which is why we have to return an object literal for the factory.
Here is the angular 1.5 code I found for factory:
var needsRecurse = false; var destination = copyType(source); if (destination === undefined) { destination = isArray(source) ? [] : Object.create(getPrototypeOf(source)); needsRecurse = true; }
Angular source code snippet for the factory() function:
function factory(name, factoryFn, enforce) { return provider(name, { $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn }); }
It takes the name and the factory function that is passed and returns a provider with the same name, that has a $get method which is our factory function. Whenever you ask the injector for a specific dependency, it basically asks the corresponding provider for an instance of that service, by calling the $get() method. That's why $get() is required, when creating providers.
Here is the angular 1.5 code for service.
function service(name, constructor) { return factory(name, ['$injector', function($injector) { return $injector.instantiate(constructor); }]); }
It turns out that when we call service(), it actually calls factory()! However, it doesn't just pass our service constructor function to the factory as is. It also passes a function that asks the injector to instantiate an object by the given constructor.
In other words, if we inject MyService somewhere, what happens in the code is:
MyServiceProvider.$get(); // return the instance of the service
To restate it again, a service calls a factory, which is a $get() method on the corresponding provider. Moreover, $injector.instantiate() is the method that ultimately calls Object.create() with the constructor function. That's why we use "this" in services.
For ES5 it doesn't matter which we use: service() or factory(), it's always a factory that is called which creates a provider for our service.
You can do the exact same thing with services as well though. A service is a constructor function, however, that doesn't prevent us from returning object literals. So we can take our service code and write it in a way that it basically does the exact same thing as our factory or in other words, you can write a service as a factory to return an object.
Why do most people recommend to use factories over services? This is the best answer I've seen which comes from Pawel Kozlowski's book: Mastering Web Application Development with AngularJS.
The factory method is the most common way of getting objects into AngularJS dependency injection system. It is very flexible and can contain sophisticated creation logic. Since factories are regular functions, we can also take advantage of a new lexical scope to simulate "private" variables. This is very useful as we can hide implementation details of a given service."
- With the factory you actually create an object inside of the factory and return it.
- With the service you just have a standard function that uses the
this
keyword to define function. - With the provider there's a
$get
you define and it can be used to get the object that returns the data.
There are three ways of handling business logic in AngularJS: ( Inspired by Yaakov's Coursera AngularJS course ) which are:
- 服务
- 厂
- 提供商
Here we are only going to talk about Service vs Factory
SERVICE :
句法:
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>
The main features of Service:
-
Lazily Instantiated : If the service is not injected it won't be instantiated ever. So to use it you will have to inject it to a module.
-
Singleton : If it is injected to multiple modules, all will have access to only one particular instance. That is why, it is very convenient to share data across different controllers.
FACTORY
Now let's talk about the Factory in AngularJS
First let's have a look at the syntax :
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; }
Now using the above two in the controller:
var factoryOne = NameOfTheFactoryOne() //since it returns a function factoryOne.someMethod(); var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object factoryTwo.someMethod();
Features of Factory:
-
This types of services follow the factory design pattern . The factory can be thought of as a central place that creates new objects or methods.
-
This does not only produce singleton, but also customizable services.
-
The
.service()
method is a factory that always produces the same type of service, which is a singleton. There is no easy way to configure it's behavior. That.service()
method is usually used as a shortcut for something that doesn't require any configuration whatsoever.
For short and simple explanation refer https://stackoverflow.com/a/26924234/5811973 .
For detailed explanation refer https://stackoverflow.com/a/15666049/5811973 .
Also from angularJs documentation:
You can understand the difference with this analogy – Consider the difference between a normal function that will return some value and constructor function that will get instantiated using new keyword.So creating factory is just similar to create normal function that will return some value(primitive or an object) whereas creating service is like creating constructor function(OO class) of which we can create instance using new keyword. The only thing to notice is here is that when we use Service method to create services it will automatically create instance of it using dependency injection mechanism supported by AngularJS