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

时间:2013-09-22 02:35:24

标签: angularjs angularjs-service angularjs-factory

  

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

但是,当你在工厂使用服务时,我仍然无法弄明白。

据我所知,工厂通常用于创建可由多个控制器调用的“常用”功能:Creating common controller functions

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

那么何时会使用服务?

是否有可能通过服务完成或更容易完成的事情?

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

这是一个例子。除了声明的方法,它们看起来完全相同,我无法弄清楚为什么我会做一个与另一个。 http://jsfiddle.net/uEpkE/

更新:来自Thomas的回答似乎暗示服务是为了更简单的逻辑和工厂用于更复杂的逻辑与私有方法,所以我更新了下面的小提琴代码,似乎两者都能够支持私人职能?

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

9 个答案:

答案 0 :(得分:276)

说明

你在这里有不同的东西:

首先:

  • 如果您使用服务,则会获得功能实例(“this” 关键词)。
  • 如果您使用工厂,您将获得返回的值 调用函数引用(工厂中的return语句)。

参考: angular.service vs angular.factory

第二名:

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

第三:

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

为什么?

  

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

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


用法

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

工厂:可以用于返回一个“类”函数,然后可以将其创建为创建实例。

因此,在您的服务中使用复杂逻辑时使用工厂您不希望暴露此复杂性

在其他情况下如果您想要返回服务实例,请使用服务

但是你会发现,我认为你会在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

  

“如果您希望将函数调用为正常函数,请使用   的 工厂 即可。如果您希望使用new实例化您的函数   运营商,使用服务。如果您不知道差异,请使用工厂。“


更新:

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

从这个页面:

  

“工厂和服务是最常用的配方。它们之间的唯一区别是服务配方更适合自定义类型的对象,而Factory可以生成JavaScript原语和功能。”

答案 1 :(得分:109)

allernhwkim最初在此问题上发布了an answer链接到his blog,但主持人已将其删除。它是我发现的唯一一个不仅告诉您如何与服务,提供商和工厂做同样事情的帖子,而且还告诉您如何与提供商一起做,你可以& #39; t a factory,以及工厂,你可以提供服务。

直接来自他的博客:

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.   
  3. 当您需要实例化一个对象时使用Factory,即new   客户(),新评论()等

  4.   
  5. 需要配置时使用Provider。即测试网址,质量保证网址,   生产网址。

  6.   

如果您发现刚刚在工厂返回一个物体,您应该使用服务。

不要这样做:

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

改为使用服务:

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

答案 2 :(得分:19)

所有这些提供商的概念比最初出现的要简单得多。如果你剖析了一个提供者并提取了不同的部分,那就非常清楚了。

简单地说,这些提供商中的每一个都是另一个的专用版本,按此顺序:provider> factory> value / constant / service

提供商尽你所能,你可以在链中进一步使用提供商,这将导致编写更少的代码。如果它没有达到你想要的效果,你可以上链,你只需要编写更多的代码。

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

AngularJS providers, factories, services, etc are all the same thing http://www.simplygoodcode.com/wp-content/uploads/2015/11/angularjs-provider-service-factory-highlight.png

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

答案 3 :(得分:8)

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

那么,何时使用工厂,何时使用服务?它归结为您的编码偏好,而不是其他任何东西。如果你喜欢模块化JS模式,那就去工厂吧。如果您喜欢构造函数(“class”)样式,那么请转到该服务。请注意,这两种样式都支持私有成员。

从OOP的角度来看,服务的优势可能是更直观:创建“类”,并与提供程序一起,跨模块重用相同的代码,并改变实例化对象的行为只需在配置块中为构造函数提供不同的参数即可。

答案 4 :(得分: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'  

但是如果一个大的服务常量,这个\会使代码难以读取。 此外,服务原型不会看到私人成员 - 只有公众可以使用:

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更方便。由于工厂没有这些缺点。我建议默认使用它。

答案 5 :(得分:2)

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

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

同时服务是一个单例,所以我们只能创建一个,可能不是创建,但是当我们注入一个控制器时我们只有一个实例,所以一个服务提供更多像公共服务(休息电话,功能......)给控制器。

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

答案 6 :(得分:0)

<强>服务

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

用法:通过简单地向注入的函数引用附加()来共享对调用有用的实用程序函数非常有用。也可以使用injectArg.call(this)或类似的方式运行。

<强>工厂

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

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

用法:对于返回一个“类”函数非常有用,该函数可以随后用于创建实例。

<强>提供商

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

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

用法:对于返回一个“类”函数非常有用,该函数可以随后用于创建实例,但在注入之前需要某种配置。对于可跨项目重用的类可能有用吗?在这一点上仍然有些朦胧。

答案 7 :(得分:0)

可以同时使用 创建对象或j 以便从两者访问

  

您可以从服务

创建新对象
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();
})

注意:

  • service默认返回object而不是构造函数。
  • 这就是构造函数设置为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默认返回构造函数而不是对象。
  • 这就是为什么可以使用构造函数创建新对象的原因。
  

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

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

结论:

  • 您可以按照您想要的方式使用 是否创建新对象或 只是为了访问简单的功能
  • 使用其中一个
  • ,不会有任何性能损失
  • 两者都是单例对象,每个应用程序只创建一个实例。
  • 每个传递参考的只有一个实例。
  • 在角度文档工厂称为服务服务称为服务

答案 8 :(得分:0)

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

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

有五种创建服务的方法:值,工厂,服务,提供者和常量。您可以在angular service处了解有关此内容的更多信息,本文通过实际的演示示例来说明所有这些方法。