首页 文章

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

提问于
浏览
288

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

However I still can't figure out when you'd use service over factory.

从我可以告诉工厂通常用于创建可由多个控制器调用的"common"函数:Creating common controller functions

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

So when would one use service?

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

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

在这里's an example. Other than the method of declaration, they seem identical and I can'弄清楚为什么我会做一个与另一个 . http://jsfiddle.net/uEpkE/

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

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

8 回答

  • 273

    解释

    你有不同的东西:

    First:

    • 如果您使用服务,您将获得 the instance of a function (“ this ”关键字) .

    • 如果您使用工厂,您将获得 the value that is returned by invoking the function reference (工厂中的退货声明) .

    参考:angular.service vs angular.factory

    Second:

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

    Third:

    使用一个或另一个(服务或工厂)是关于代码风格 . 但是,AngularJS中的 common way 是使用 factory .

    为什么?

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

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


    用法

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

    工厂:可以用于返回“类”功能,然后可以创建新的实例 .

    所以, use a factory when you have complex logic 在你的服务和 you don't want expose this complexity .

    在其他情况下 if you want to return an instance of a service just use service .

    但随着时间的推移,你会发现在我认为80%的情况下你会使用工厂 .

    有关详细信息:http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/


    UPDATE :

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

    “如果您希望像普通函数一样调用函数,请使用factory . 如果您希望使用new运算符实例化函数,请使用service . 如果您不知道其中的差异,请使用factory . ”


    UPDATE :

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

    从这个页面:

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

  • 0

    allernhwkim最初在此问题上发布了an answer链接到his blog,但主持人删除了它 . 它's the only post I'已找到哪个与工厂没有't just tell you how to do the same thing with service, provider and factory, but also tells you what you can do with a provider that you can'吨,而且工厂没有服务 .

    直接来自他的博客:

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

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

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

    看看它是如何 生产环境 汽车的工厂 .

    他博客的结论非常好:

    总之,---------------------------------------------- -----
    |供应商|辛格尔顿|实例化|配置|


    |工厂|是的|是的|没有|


    |服务|是的|没有|没有|


    |供应商|是的|是的|是的|


    当你只需要一个简单的对象(例如Hash)时使用Service,例如{foo; 1,bar:2}它很容易编码,但是你无法实例化它 . 需要实例化对象时使用Factory,即新Customer(),新Comment()等 . 需要配置时使用Provider . 即测试网址,质量保证网址, 生产环境 网址 .

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

    不要这样做:

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

    改为使用服务:

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

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

    简而言之,这些提供者中的每一个都是另一个的专用版本,按此顺序: provider > factory > value / constant / service .

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

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

    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/

  • 0

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

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

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

  • 8

    与服务相比,工厂无法做到或做得更好 . 反之亦然 . 工厂似乎更受欢迎 . 原因是它处理私人/公共成员的便利性 . 在这方面,服务会更加笨拙 . 在对服务进行编码时,您倾向于通过“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更方便 . 由于工厂没有这些缺点 . 我建议默认使用它 .

  • 2

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

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

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

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

  • 2

    Services

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

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

    Factories

    Syntax :module.factory('factoryName',function);

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

    Usage :可以用于返回'class'函数,然后可以将其创建为创建实例 .

    Providers

    Syntax :module.provider('providerName',function);

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

    Usage :可能对返回一个'class'函数很有用,然后可以新建这个函数来创建实例但需要某种配置在被注射之前对于可跨项目重用的类可能有用吗?在这一个仍然有点朦胧 .

  • 19

    可以同时使用 the way you want :两者是 create object 还是j ust to access functions


    您可以从服务创建新对象

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

    结论:

    • 您既可以使用 the way you want 来创建新对象,也可以只访问简单函数

    • 不会有任何性能损失,使用一个而不是另一个

    • 两者都是单例对象,每个应用程序只创建一个实例 .

    • 只是每个传递引用的实例 .

    • 在角度文档 factory is called serviceservice is called service 中 .

相关问题