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

AngularJS : When to use service instead of factory

Please bear with me here. I know there are other answers such as:
AngularJS: Service vs provider vs factory

但我还是搞不清你们什么时候在工厂使用服务。

据我所知,工厂通常用于创建可由多个控制器调用的"公共"函数:创建公共控制器函数

角度文件似乎更喜欢工厂而不是服务。他们甚至在使用工厂时提到"服务",这更让人困惑!http://docs.angularjs.org/guide/dev_guide.services.creating_服务

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

有什么东西是唯一可能的还是更容易做的服务?

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

下面是一个例子。除了声明方法之外,它们似乎是相同的,我不明白为什么我要做一个对另一个。http://jsfiddle.net/uepke/

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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"关键字)。
  • 如果使用工厂,您将获得调用函数引用(工厂中的返回语句)。

参考:角度服务与角度工厂

第二:

请记住,AngularJS中的所有供应商(价值、常量、服务、工厂)都是单件产品!

第三:

使用一个或另一个(服务或工厂)是关于代码样式的。但是,在安格拉尔,通常的方法是使用工厂。

为什么?

Because"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."

(参考:http://www.amazon.com/mastering web application development angularjs/dp/1782161821)。

用法

服务:对于共享实用程序函数很有用,只需将()附加到注入的函数引用即可调用这些函数。也可以与injectedArg.call(this)或类似产品一起运行。

factory:对于返回"class"函数很有用,该函数随后可以被新建以创建实例。

所以,当您的服务中有复杂的逻辑,并且不希望暴露这种复杂性时,可以使用工厂。

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

但随着时间的推移,我想80%的情况下都会用到工厂。

更多详细信息:http://blog.manishchabra.com/2013/09/angularjs-service-vs-factory-with-example/

更新:

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

"If you want your function to be called like a normal function, use
factory. If you want your function to be instantiated with the new
operator, use service. If you don't know the difference, use factory."

更新:

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

从本页开始:

"Factory and Service are the most commonly used recipes. The only difference between them is that Service recipe works better for objects of custom type, while Factory can produce JavaScript primitives and functions."


Allernhwkim最初在他的博客链接上发布了一个关于这个问题的答案,但是一个版主删除了它。这是我发现的唯一一篇文章,它不仅告诉你如何对服务、供应商和工厂做同样的事情,还告诉你你可以对供应商做什么,你不能对工厂做什么,对工厂做什么,你不能对服务做什么。

直接从他的博客:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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是一个对象而不是一个函数。

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

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

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

1
2
3
4
5
6
7
8
9
10
app.factory('CarFactory', function() {
    function Car(numCylinder) {
        this.dealer="Bad";
        this.numCylinder = numCylinder
    };
    Car.prototype.breakCylinder = function() {
        this.numCylinder -= 1;
    };
    return Car;
});

看看它到底是一家生产汽车的工厂。

他的博客的结论很好:

In conclusion,

1
2
3
4
5
6
7
8
9
---------------------------------------------------  
| 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.

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

    不要这样做:

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

    改用服务:

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


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

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

    只要提供者做了你能做的,你就可以进一步使用提供者,这将导致编写更少的代码。如果它不能完成你想要的,你就可以走上这个链条,你只需要写更多的代码。

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

    AngularJS供应商、工厂、服务等都是一样的,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/


    工厂和服务都会生成singleton对象,这些对象可以由提供者配置并注入控制器和运行块中。从被注射者的角度来看,无论是来自工厂还是服务,都没有任何区别。

    那么,什么时候使用工厂,什么时候使用服务?归根结底,这取决于您的编码偏好,而不是其他。如果你喜欢模块化JS模式,那就去工厂吧。如果您喜欢构造器函数("class")样式,那么就使用该服务。请注意,这两种样式都支持私有成员。

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


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

    工厂因为不是单例的,所以在注入时可以创建任意多的工厂,因此它的工作方式与对象工厂类似。您可以创建域实体的工厂,并更轻松地处理这些对象,这些对象可能类似于模型的对象。当你检索到几个对象时,你可以在这个对象中映射它们,它可以在DDBB和AngularJS模型之间扮演另一个层的角色。你可以向对象添加方法,这样你就可以更加关注对象了。

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

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


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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传递到控制器的实例也有相同的缺点。当然,您可以通过使用这个/那个来克服这个问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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'

    但是如果有一个大的服务常量,这个ing会使代码的可读性变差。此外,服务原型将看不到私有成员,只有公共成员可以使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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'

    综上所述,使用工厂更方便。因为工厂没有这些缺点。我建议在默认情况下使用它。


    可以使用这两种方式:创建对象还是只从两者访问函数

    You can create new object from service

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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属性的原因。
    • 由于此服务将返回对象,但该对象内部将是用于创建新对象的构造函数函数;

    You can create new object from factory

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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();
    })

    注:

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

    Create service for just accessing simple functions

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    app.service('carservice', function () {
       this.createCar = function () {
           console.log('createCar');
       };
       this.deleteCar = function () {
           console.log('deleteCar');
       };
    });

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

    Create factory for just accessing simple functions

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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()
    })

    结论:

    • 无论是创建新对象还是只需访问简单的函数
    • 不会有任何性能影响,使用一个对另一个
    • 两者都是单例对象,每个应用程序只创建一个实例。
    • 只是一个实例,每个实例都传递引用。
    • 在Angular文档中,工厂被称为服务,也被称为服务。

    服务

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

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

    工厂

    语法:module.factory("factoryname",函数);

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

    用法:对于返回"class"函数很有用,该函数随后可以被新建以创建实例。

    提供者

    语法:module.provider("providername",函数);

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

    用法:对于返回"class"函数很有用,该函数可以是新的,用于创建实例,但在注入之前需要某种配置。可能对可跨项目重用的类有用?还是有点模糊。