请耐心听我说。我知道还有其他答案,比如: AngularJS:服务vs提供商vs工厂

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

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

比起服务,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()
    ];
}

当前回答

服务

语法:模块。service('serviceName',函数); 结果:当将serviceName声明为可注入参数时,你将得到传递给module.service的实际函数引用。

使用方法:可以通过简单地将()附加到注入的函数引用来共享有用的实用程序函数。也可以用injectedArg运行。调用(这个)或类似的方法。

工厂

语法:模块。factory('factoryName',函数);

结果:当将factoryName声明为一个可注入参数时,你将得到通过调用传递给module.factory的函数引用返回的值。

用法:可能用于返回一个'class'函数,然后可以重新创建实例。

供应商

语法:模块。provider('providerName',函数);

结果:当将providerName声明为一个可注入参数时,您将获得通过调用传递给module.provider的函数引用的$get方法返回的值。

用途:可能用于返回一个'类'函数,然后可以重新创建实例,但在注入之前需要某种配置。也许对跨项目可重用的类有用?我还是不太清楚。

其他回答

所有这些提供者的概念都比最初看起来要简单得多。如果你仔细分析一个提供程序,把它的不同部分拿出来,就会非常清楚。

简单地说,这些提供者中的每一个都是另一个的专门版本,顺序是:提供者>工厂>值/常量/服务。

只要提供程序做了你能做的,你就可以在链的更下方使用它,这将导致编写更少的代码。如果它不能完成你想要的,你可以继续往上走,你只需要写更多的代码。

这张图说明了我的意思,在这张图中,你将看到一个提供者的代码,突出显示的部分显示了提供者的哪些部分可以用来创建工厂、值等。

(来源:simplygoodcode.com)

要了解更多细节和例子,请访问:http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/

服务

语法:模块。service('serviceName',函数); 结果:当将serviceName声明为可注入参数时,你将得到传递给module.service的实际函数引用。

使用方法:可以通过简单地将()附加到注入的函数引用来共享有用的实用程序函数。也可以用injectedArg运行。调用(这个)或类似的方法。

工厂

语法:模块。factory('factoryName',函数);

结果:当将factoryName声明为一个可注入参数时,你将得到通过调用传递给module.factory的函数引用返回的值。

用法:可能用于返回一个'class'函数,然后可以重新创建实例。

供应商

语法:模块。provider('providerName',函数);

结果:当将providerName声明为一个可注入参数时,您将获得通过调用传递给module.provider的函数引用的$get方法返回的值。

用途:可能用于返回一个'类'函数,然后可以重新创建实例,但在注入之前需要某种配置。也许对跨项目可重用的类有用?我还是不太清楚。

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

A factory because is not a singleton, you can create as many as you want when you inject, so it works like a factory of objects. You can create a factory of an entity of your domain and work more comfortably with this objects which could be like an object of your model. When you retrieve several objects you can map them in this objects and it can act kind of another layer between the DDBB and the AngularJs model.You can add methods to the objects so you oriented to objects a little bit more your AngularJs App.

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

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

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返回一个函数,所以你可以在你的控制器中做新的CarFactory,传递一些特定于那辆车的圆柱体。你不能创建新的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;
});

看看它是如何字面上生产汽车的工厂。

他博客的结论很好:

In conclusion, --------------------------------------------------- | Provider| Singleton| Instantiable | Configurable| --------------------------------------------------- | Factory | Yes | Yes | No | --------------------------------------------------- | Service | Yes | No | No | --------------------------------------------------- | Provider| Yes | Yes | Yes | --------------------------------------------------- Use Service when you need just a simple object such as a Hash, for example {foo;1, bar:2} It’s easy to code, but you cannot instantiate it. Use Factory when you need to instantiate an object, i.e new Customer(), new Comment(), etc. Use Provider when you need to configure it. i.e. test url, QA url, production url.

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

不要这样做:

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

改用service:

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

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

那么,什么时候使用工厂,什么时候使用服务?这可以归结为您的编码偏好,而不是其他。如果你喜欢模块化JS模式,那就选择工厂模式。如果你喜欢构造函数(“类”)风格,那么就选择服务。注意,这两种样式都支持私有成员。

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