299

请在这里忍受我。我知道还有其他答案,例如: AngularJS: Service vs provider vs factory

但是我仍然无法弄清楚您何时使用工厂服务。

据我所知,工厂通常用于创建可以被多个控制器调用的“通用”函数:创建通用控制器函数

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

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

是否有一些事情只有通过服务才能实现或更容易完成?

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

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

更新:从托马斯的回答看来,服务是为了更简单的逻辑而工厂是为了更复杂的逻辑和私有方法,所以我更新了下面的小提琴代码,似乎两者都能够支持私有函数?

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

9 回答 9

283

解释

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

第一的:

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

参考: angular.service 与 angular.factory

第二:

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

第三:

使用其中一个(服务或工厂)与代码风格有关。但是,AngularJS 中的常用方法是使用factory

为什么 ?

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

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


用法

Service :对于共享实用函数很有用,这些实用函数只需附加()到注入的函数引用即可调用。也可以运行injectedArg.call(this)或类似。

Factory :对于返回“类”函数可能很有用,然后可以新建该函数以创建实例。

因此,当您的服务中有复杂的逻辑并且您不想暴露这种复杂性时,请使用工厂

在其他情况下,如果您想返回服务实例,只需使用 service

但是随着时间的推移,你会看到我认为在 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

“如果您希望您的函数像普通函数一样被调用,请使用 factory。如果您希望您的函数使用 new 运算符实例化,请使用 service。如果您不知道区别,请使用 factory。”


更新 :

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

从这个页面:

“Factory 和 Service 是最常用的配方。它们之间的唯一区别是 Service recipe 更适用于自定义类型的对象,而 Factory 可以生成 JavaScript 原语和函数。”

于 2013-09-22T08:31:27.630 回答
112

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

这显示了 CarService 将如何始终生产具有 4 个气缸的汽车,您无法为单个汽车更改它。而 CarFactory 返回一个函数,您可以new CarFactory在控制器中执行此操作,并传入特定于该汽车的多个气缸。你不能这样做new CarService,因为 CarService 是一个对象而不是一个函数。

工厂不这样工作的原因:

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

并自动返回一个函数供您实例化,因为那样您就不能这样做(将东西添加到原型/等):

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

看看它实际上是一家生产汽车的工厂。

他博客的结论非常好:

综上所述,

---------------------------------------------------  
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------  
| Factory | Yes      | Yes          | No          |
---------------------------------------------------  
| Service | Yes      | No           | No          |
---------------------------------------------------  
| Provider| Yes      | Yes          | Yes         |       
---------------------------------------------------  
  1. 当您只需要一个简单的对象(例如 Hash)时使用 Service,例如 {foo;1, bar:2} 它很容易编码,但您无法实例化它。

  2. 当需要实例化一个对象时使用Factory,即new Customer()、new Comment()等。

  3. 需要配置时使用Provider。即测试网址、质量检查网址、生产网址。

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

不要这样做:

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

改用服务:

app.service('CarService', function() {
    this.numCylinder = 4;
});
于 2014-12-03T04:52:28.980 回答
21

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

简单地说,这些提供者中的每一个都是另一个的专用版本,按以下顺序:provider> factory> value// constantservice

只要提供者尽您所能,您就可以在链的更下游使用提供者,这将导致编写更少的代码。如果它没有完成你想要的,你可以继续往上走,你只需要编写更多的代码。

此图说明了我的意思,在此图中,您将看到提供程序的代码,突出显示的部分向您显示提供程序的哪些部分可用于创建工厂、值等。

AngularJS 提供者、工厂、服务等都是同一个东西
(来源:simplygoodcode.com

有关我从中获取图像的博客文章的更多详细信息和示例,请访问:http ://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/

于 2015-11-19T19:54:55.717 回答
8

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

那么,什么时候使用工厂,什么时候使用服务呢?它归结为您的编码偏好,仅此而已。如果你喜欢模块化 JS 模式,那就去工厂吧。如果你喜欢构造函数(“类”)风格,那就去服务吧。请注意,两种样式都支持私有成员。

服务的优点可能是从 OOP 的角度来看它更直观:创建一个“类”,并与提供者一起,跨模块重用相同的代码,并通过提供简单的方式改变实例化对象的行为配置块中构造函数的不同参数。

于 2014-09-09T08:22:57.327 回答
2

与服务相比,工厂没有什么不能做或做得更好。反之亦然。工厂似乎更受欢迎。这样做的原因是它在处理私人/公共成员方面很方便。在这方面,服务会更加笨拙。在编写服务时,您倾向于通过“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”关键字为您创建服务,因此 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'  

但是如果 Service 常量很大,this\that-ing 会使代码的可读性很差。此外,服务原型不会看到私有成员——他们只能使用公共成员:

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'

总结起来,使用Factory更方便。As Factory 没有这些缺点。我建议默认使用它。

于 2015-07-18T11:01:46.697 回答
2

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

工厂因为不是单例,所以你可以在注入时创建任意数量的工厂,因此它的工作方式类似于对象工厂。您可以创建域实体的工厂,并更舒适地使用这些对象,这些对象可能就像您的模型对象。当您检索多个对象时,您可以将它们映射到此对象中,它可以充当 DDBB 和 AngularJs 模型之间的另一层。您可以向对象添加方法,以便您在 AngularJs 应用程序中更多地面向对象。

同时一个服务是一个单例,所以我们只能创建一个,也许不能创建,但是当我们注入控制器时我们只有一个实例,所以一个服务提供更像一个普通的服务(休息调用,功能......)给控制器。

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

于 2015-10-23T10:10:52.877 回答
0

服务

语法: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 方法返回的值。

用法:对于返回一个“类”函数可能很有用,然后可以新建该函数以创建实例,但这需要在注入之前进行某种配置。也许对跨项目可重用的类有用?这个还是有点朦胧。

于 2015-04-27T13:18:15.193 回答
0

可以同时使用你想要的两种方式:无论是创建对象还是只是从两者访问函数


您可以从服务创建新对象

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 属性的原因。
  • 由于此服务将返回对象,但是但是在该对象内部将是构造函数,该构造函数将用于创建新对象;

您可以从工厂创建新对象

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

笔记 :

  • factory 默认返回构造函数而不是 object 。
  • 这就是为什么可以使用构造函数创建新对象的原因。

创建仅用于访问简单功能的服务

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

.controller('MyService', function ($scope,carservice) { 
    carservice.createCar()
})

创建工厂仅用于访问简单功能

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

结论 :

  • 您可以使用您想要的方式来创建新对象或只是访问简单的功能
  • 使用其中一个不会有任何性能损失
  • 两者都是单例对象,每个应用程序只创建一个实例。
  • 在传递引用的每个地方都只有一个实例。
  • 在角度文档中,工厂称为服务服务也称为服务
于 2016-06-30T22:05:37.160 回答
0

工厂和服务是最常用的方法。它们之间的唯一区别是 Service 方法更适合需要继承层次结构的对象,而 Factory 可以生成 JavaScript 原语和函数。

Provider 函数是核心方法,所有其他的只是它的语法糖。只有在构建需要全局配置的可重用代码时才需要它。

创建服务有五种方法:Value、Factory、Service、Provider 和 Constant。您可以在此处了解有关此角度服务的更多信息,本文通过实际演示示例解释了所有这些方法。

.

于 2019-05-14T18:09:08.767 回答