AngularJS:何时使用服务而不是工厂

请在这里忍受我。 我知道还有其他答案,如: AngularJS:服务vs提供者vs工厂

但是,我仍然不知道什么时候你会使用服务超过工厂。

从我可以告诉工厂通常用来创build可以被多个控制器调用的“通用”function: 创build通用控制器function

Angular文档似乎更喜欢工厂而不是服务。 甚至在使用工厂时甚至提到“服务”,这更令人困惑! http://docs.angularjs.org/guide/dev_guide.services.creating_services

那么,什么时候会使用服务?

有没有什么东西只能通过服务完成或者更容易完成?

幕后有什么不同吗? 性能/内存差异?

这是一个例子。 除了声明的方法之外,它们看起来完全相同,我不知道为什么我会做一个。 http://jsfiddle.net/uEpkE/

更新:从托马斯的答案似乎暗示服务是更简单的逻辑和工厂更复杂的逻辑与私人方法,所以我更新了下面的小提琴代码,似乎都能够支持私人function?

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

说明

你在这里得到不同的东西:

第一:

  • 如果您使用服务,您将获得一个函数 (“ this ”关键字) 的实例
  • 如果您使用工厂,您将获得通过调用函数引用 (工厂中的return语句) 返回的值

ref: angular.service vs angular.factory

第二:

请记住,AngularJS中的所有提供者(价值,常量,服务,工厂)都是单身人士!

第三:

使用一个或另一个(服务或工厂)是关于代码风格。 但是,AngularJS的常见方式是使用工厂

为什么?

因为 “工厂方法是将对象获取到AngularJSdependency injection系统中最常用的方式,它非常灵活,可以包含复杂的创build逻辑,由于工厂是常规函数,我们还可以利用新的词法范围来模拟”私有“variables,这是非常有用的,因为我们可以隐藏给定服务的实现细节。”

参考 : http : //www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821 )。


用法

服务:可以通过简单地追加()到注入的函数引用来共享对调用有用的实用程序函数。 也可以运行injectedArg.call(this)或类似的。

工厂:可能会有用的返回一个“类”的function,然后可以新build立实例。

所以, 当你的服务中有复杂的逻辑时使用工厂,你 不想暴露这种复杂性

在其他情况下, 如果你想返回一个服务的实例只使用服务

但是,随着时间的推移,你会看到80%的案例都会使用工厂。

欲了解更多详情,请访问: http : //blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/


更新:

优秀的职位在这里: http : //iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html

“如果你想让你的函数像普通函数一样被调用 ,那么使用工厂 ,如果你想用新的操作符实例化你的函数,请使用service,如果你不知道区别,请使用factory。


更新:

AngularJS团队做他的工作,并给出一个解释: http : //docs.angularjs.org/guide/providers

并从此页面:

“工厂和服务”是最常用的配方,它们唯一的区别在于“服务配方”对于自定义types的对象更好,而“工厂”则可以生成JavaScript原语和函数。

allernhwkim最初发布了一个关于这个问题的答案链接到他的博客 ,但是一个版主删除了它。 这是我发现的唯一一个不仅告诉你如何在服务,提供者和工厂方面做同样的事情的职位,而且还告诉你可以用一个你不能在工厂工作的提供者做什么,一个你不能提供服务的工厂。

直接从他的博客:

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

这显示了汽车服务将如何总是生产一个4缸汽车,你不能改变个人汽车。 鉴于CarFactory返回一个函数,所以你可以在你的控制器做new CarFactory ,传入特定于该汽车的一些气瓶。 你不能做new CarService因为CarService是一个对象而不是函数。

工厂不这样工作的原因是:

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

并自动返回一个函数为你实例化,是因为你不能这样做(添加到原型/ etc的东西):

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

看看它是怎么一个工厂生产汽车。

他的博客的结论是相当不错的:

结论是,

 --------------------------------------------------- | Type | Singleton| Instantiable | Configurable| --------------------------------------------------- | Factory | Yes | No | No | --------------------------------------------------- | Service | Yes | Yes | No | --------------------------------------------------- | Provider| Yes | Yes | Yes | --------------------------------------------------- 
  1. 当你只需要一个简单的对象,比如一个Hash,例如{foo; 1,bar:2},就可以使用工厂。编码很简单,但是你不能实例化它。

  2. 当你需要实例化一个对象,例如新的Customer(),新的Comment()等等时使用Service。

  3. 使用提供者,当你需要configuration它。 即testingurl,QAurl,制作url。

如果你发现你只是在工厂返回一个对象,你应该使用服务。

不要这样做:

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

改用服务:

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

所有这些提供者的概念比最初看起来简单得多。 如果你解剖一个提供者,并且拉出不同的部分,就会变得非常清楚。

简单地说,这些提供者中的每一个都是另一个提供者的专用版本,依次为: provider > factory > value / constant / service

只要提供者做了你所能做的事情,你就可以使用提供者进一步下去,这会导致编写更less的代码。 如果它没有达到你想要的,你可以上链,你只需要编写更多的代码。

这张图片说明了我的意思,在这张图片中,您将看到供应商的代码,突出显示的部分显示供应商的哪些部分可用于创build工厂,价值等。

AngularJS提供者,工厂,服务等都是一样的东西wp-content/uploads/2015/11/angularjs-provider-service-factory-highlight.png

有关详细信息和来自博客文章的示例,请点击以下url : http : //www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/

工厂和服务都会产生单个对象,这些对象可以由提供者configuration并注入到控制器和运行块中。 从注射器的angular度来看,对象是来自工厂还是服务对象是完全没有区别的。

那么,何时使用工厂,何时使用服务? 这归结于您的编码偏好,没有别的。 如果你喜欢模块化的JS模式,那么去工厂。 如果你喜欢构造函数(“类”)风格,然后去服务。 请注意,这两种风格都支持私有成员

从OOP的angular度来看,服务的优势可能更为直观:创build一个“类”,并与提供者一起在模块之间重复使用相同的代码,并简单地通过提供实例化对象的行为configuration块中的构造函数有不同的参数。

没有什么工厂做不了,或者与服务相比,做得更好。 反之亦然。 工厂似乎更受欢迎。 其原因是它在处理私人/公众成员方面的便利。 在这方面服务会更笨拙。 在对服务进行编码时,您倾向于通过“this”关键字将对象成员公开,并可能突然发现这些公共成员对私有方法(即内部函数)是不可见的。

 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使用“new”关键字为您创build一个服务,所以Angular传递给控制器​​的实例也会有相同的缺点。 当然你可以用这个/那个来解决这个问题:

 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' 

但是,对于一个大的服务常量来说,这会使代码难以阅读。 此外,服务原型将不会看到私人成员 – 只有公众可以获得:

 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' 

总结一下,使用工厂更方便。 由于工厂没有这些缺点。 我会build议使用它默认情况下。

即使他们说所有的服务和工厂都是单身,我也不完全同意。 我会说工厂不是单身人士,这就是我的答案。 我真的会考虑定义每个组件(服务/工厂)的名称,我的意思是:

一个工厂,因为不是一个单身人士,你可以创build尽可能多的,当你注入,所以它像一个对象的工厂。 你可以创build一个你的域的实体的工厂,更舒适地使用这个对象,它可以像你的模型的对象。 当你检索几个对象时,你可以将它们映射到这个对象中,并且它可以在DDBB和AngularJs模型之间起到另一个层的作用。你可以向对象添加方法,这样你就可以将更多的对象添加到你的AngularJs应用程序中。

同时一个服务是一个单身人士,所以我们只能创build一个,也许不能创build,但是当我们注入一个控制器的时候,我们只有一个实例,所以一个服务提供的更像一个普通的服务(rest调用,function..)到控制器。

从概念上讲,你可以认为像服务提供服务,工厂可以创build一个类的多个实例(对象)

服务

语法 :module.service('serviceName',function); 结果 :将serviceName声明为注入参数时,将提供传递给module.service的实际函数引用。

用法 :对于通过简单追加()到注入的函数引用来调用有用的共享实用程序函数可能很有用。 也可以运行injectArg.call(this)或类似的。

工厂

语法 :module.factory('factoryName',function);

结果 :将factoryName声明为注入参数时,将提供通过调用传递给module.factory的函数引用返回的值。

用法 :可以用于返回一个“类”函数,然后可以创build新的实例。

供应商

语法 :module.provider('providerName',function);

结果 :将providerName声明为注入参数时,将提供通过调用传递给module.provider的函数引用的$ get方法返回的值。

用法 :可以用于返回一个'class'函数,然后可以new'ed创build实例,但需要某种configuration之前被注入。 对于可跨项目重用的类也许有用? 这件事还是有点朦胧。

可以同时使用两种方式 :无论是创build对象还是从两者访问函数


您可以从服务创build新的对象

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

注意 :

  • 服务默认返回对象而不是构造函数。
  • 所以这就是为什么构造函数被设置为this.model属性。
  • 由于这个服务将返回对象,但是但是在这个对象内部将是构造函数,它将被用来创build新的对象;

您可以从工厂创build新的对象

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

注意 :

  • 工厂默认返回构造函数而不是对象。
  • 所以这就是为什么可以用构造函数创build新的对象。

创build服务只是访问简单的function

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

创build工厂只是访问简单的function

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

结论:

  • 你可以使用你想要的方式创build新的对象,或者只是访问简单的函数
  • 不会有任何性能问题
  • 两者都是单例对象,每个应用程序只能创build一个实例。
  • 只有一个实例,每个参考被传递的地方。
  • 在angular度文档工厂被称为服务 ,也是服务被称为服务