对服务与工厂感到困惑

Posted

技术标签:

【中文标题】对服务与工厂感到困惑【英文标题】:Confused about Service vs Factory 【发布时间】:2012-11-25 13:56:11 【问题描述】:

据我了解,在工厂内部时,我返回一个注入控制器的对象。在服务内部时,我使用this 处理对象并且不返回任何内容。

我假设服务总是单例,并且新工厂对象会被注入到每个控制器中。然而,事实证明,工厂对象也是单例?

演示示例代码:

var factories = angular.module('app.factories', []);
var app = angular.module('app',  ['ngResource', 'app.factories']);

factories.factory('User', function () 
  return 
    first: 'John',
    last: 'Doe'
  ;
);

app.controller('ACtrl', function($scope, User) 
  $scope.user = User;
);

app.controller('BCtrl', function($scope, User) 
  $scope.user = User;
);

当在ACtrl 中更改user.first 时,BCtrl 中的user.first 也发生了更改,例如User 是单身人士吗?

我的假设是新实例被注入到带有工厂的控制器中?

【问题讨论】:

在“module.service”和“module.factory”旁边还有另外两种在AngularJS中创建服务的方法。有关更多信息,请查看博文:“How to create (singleton) AngularJS services in 4 different ways” angular.service vs angular.factory的可能重复 【参考方案1】:

所有 Angular 服务都是单例的

文档(参见单例服务):https://docs.angularjs.org/guide/services

最后,重要的是要认识到所有 Angular 服务都是应用程序单例。这意味着每个注入器只有一个给定服务的实例。

服务和工厂的区别基本如下:

app.service('myService', function() 

  // service is just a constructor function
  // that will be called with 'new'

  this.sayHello = function(name) 
     return "Hi " + name + "!";
  ;
);

app.factory('myFactory', function() 

  // factory returns an object
  // you can run some code before

  return 
    sayHello : function(name) 
      return "Hi " + name + "!";
    
  
);

查看有关 $provide 的演示文稿:http://slides.wesalvaro.com/20121113/#/

这些幻灯片用于 AngularJs 聚会之一:http://blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html

【讨论】:

另见***.com/questions/15666048/…,它讨论了服务、工厂和提供之间的区别。 官方文档间接[原文如此! not enought clear] 意味着即使您使用工厂定义服务,它也只创建一次。换句话说,它不会根据参考(注入点)再次创建 - 无论你怎么称呼它。这两种方式都会导致每个注入器产生一个单例实例。 你说“服务只是一个构造函数,将用'new'调用”,但我认为这是误导。我不认为它是在幕后使用 new 调用的,我认为开发人员负责在其上调用 new @nfiniteloop,查看第 3574 行附近的源代码。工厂是提供者的 $get 方法,服务是使用在提供的函数上调用 $injector.instantiate 的方法生成工厂,然后调用 new . (See Docs) 我的印象是,一个服务就像你通过引用它来使用的单例一样。而且工厂是一个单例,每次都返回一个新对象。也就是说,一项服务将为您提供一辆“汽车”,而您项目中的所有内容都将使用这辆汽车。每次您调用工厂时,工厂都会给您一辆新车。一个是返回单例的单例,一个是返回对象的单例。谁能解释一下?将所有东西都称为单例并没有帮助,因为它可以引用多个东西。【参考方案2】:

还有一种方法可以返回构造函数,这样您就可以在工厂中返回 newable 类,如下所示:

function MyObjectWithParam($rootScope, name) 
  this.$rootScope = $rootScope;
  this.name = name;

MyObjectWithParam.prototype.getText = function () 
  return this.name;
;

App.factory('MyObjectWithParam', function ($injector) 
  return function(name)  
    return $injector.instantiate(MyObjectWithParam, name: name );
  ;
); 

因此,您可以在使用 MyObjectWithParam 的控制器中执行此操作:

var obj = new MyObjectWithParam("hello"),

在此处查看完整示例:http://plnkr.co/edit/GKnhIN?p=preview

这里是讨论它的 google 组页面: https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ

【讨论】:

我在使用您的示例时遇到了缩小问题。你知道我应该如何注释吗? 是的,存在 Angular 的缩小符号。它应该是这样的:App.factory('MyObjectWithParam', ['$injector', function ($injector) return function(name) return $injector.instantiate(MyObjectWithParam, name: name ); ; ]); 在此处阅读更多信息:docs.angularjs.org/tutorial/step_05 如果可以改用.service,为什么要这样做? 我也有同样的想法@flup。 @justgoscha,与.service 相比,使用.factory 是否有一些好处(感知?)? 我认为是因为服务是单例。我在这里构造的是基本上是一个类,它是新的。因此,您可以拥有像汽车服务工厂这样的东西,然后制作 new Car('BMW')new Car('Ford'),它们不会共享相同的变量和所有内容。【参考方案3】:

除了第一个答案,我认为 .service() 适合那些以更面向对象的风格(C#/Java)编写代码的人(使用 this 关键字并通过原型/构造函数实例化对象)。

Factory 适用于编写更自然的 javascript/函数式编码的代码的开发人员。

看看 angular.js 中的 .service 和 .factory 方法的源代码——在内部它们都调用了 provider 方法:

  function provider(name, provider_) 
    if (isFunction(provider_)) 
      provider_ = providerInjector.instantiate(provider_);
    
    if (!provider_.$get) 
      throw Error('Provider ' + name + ' must define $get factory method.');
    
    return providerCache[name + providerSuffix] = provider_;
  

  function factory(name, factoryFn)  \
    return provider(name,  $get: factoryFn ); 
  

  function service(name, constructor) 
    return factory(name, ['$injector', function($injector) 
      return $injector.instantiate(constructor);
    ]);
  

【讨论】:

【参考方案4】:

live example

“你好世界”示例

factory / service / provider

var myApp = angular.module('myApp', []);
 
//service style, probably the simplest one
myApp.service('helloWorldFromService', function() 
    this.sayHello = function() 
        return "Hello, World!"
    ;
);
 
//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() 
    return 
        sayHello: function() 
            return "Hello, World!"
        
    ;
);
    
//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() 
    // In the provider function, you cannot inject any
    // service or factory. This can only be done at the
    // "$get" method.
 
    this.name = 'Default';
 
    this.$get = function() 
        var name = this.name;
        return 
            sayHello: function() 
                return "Hello, " + name + "!"
            
        
    ;
 
    this.setName = function(name) 
        this.name = name;
    ;
);
 
//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider)
    helloWorldProvider.setName('World');
);
        
 
function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) 
    
    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
​

【讨论】:

【参考方案5】:

以下是主要区别:

服务

语法:module.service( 'serviceName', function );

结果:将 serviceName 声明为可注入参数时,您将获得传递给 module.service函数实例

用法:对于共享实用程序函数很有用,只需将 () 附加到注入的函数引用即可调用。也可以使用injectedArg.call( this ) 或类似名称运行。

工厂

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

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

用法:对于返回 'class' 函数很有用,然后可以通过 new'ed 创建实例。

还要检查 AngularJS documentation 和 *** confused about service vs factory 上的类似问题。

这里是example using services and factory。阅读有关AngularJS service vs factory 的更多信息。

【讨论】:

这对我来说很有意义。 he 工厂返回创建新对象的蓝图。【参考方案6】:

这里有更多关于服务与工厂的示例,它们可能有助于了解它们之间的区别。基本上,一个服务调用了“new ...”,它已经被实例化了。工厂不会自动实例化。

基本示例

返回一个具有单一方法的类对象

这是一个只有一个方法的服务:

angular.service('Hello', function () 
  this.sayHello = function ()  /* ... */ ;
);

这是一个工厂,它返回一个带有方法的对象:

angular.factory('ClassFactory', function () 
  return 
    sayHello: function ()  /* ... */ 
  ;
);

返回一个值

返回数字列表的工厂:

angular.factory('NumberListFactory', function () 
  return [1, 2, 3, 4, 5];
);

console.log(NumberListFactory);

返回数字列表的服务:

angular.service('NumberLister', function () 
  this.numbers = [1, 2, 3, 4, 5];
);

console.log(NumberLister.numbers);

两种情况下的输出都是一样的,都是数字列表。

高级示例

使用工厂的“类”变量

在这个例子中,我们定义了一个 CounterFactory,它递增或递减一个计数器,您可以获取当前计数或获取已创建的 CounterFactory 对象的数量:

angular.factory('CounterFactory', function () 
  var number_of_counter_factories = 0; // class variable

  return function () 
    var count = 0; // instance variable
    number_of_counter_factories += 1; // increment the class variable

    // this method accesses the class variable
    this.getNumberOfCounterFactories = function () 
      return number_of_counter_factories;
    ;

    this.inc = function () 
      count += 1;
    ;
    this.dec = function () 
      count -= 1;
    ;
    this.getCount = function () 
      return count;
    ;
  

)

我们使用CounterFactory 创建多个计数器。我们可以访问类变量来查看创建了多少计数器:

var people_counter;
var places_counter;

people_counter = new CounterFactory();
console.log('people', people_counter.getCount());
people_counter.inc();
console.log('people', people_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());

places_counter = new CounterFactory();
console.log('places', places_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());
console.log('counters', places_counter.getNumberOfCounterFactories());

这段代码的输出是:

people 0
people 1
counters 1
places 0
counters 2
counters 2

【讨论】:

这是一个有用的例子,number_of_counter_factories 就像 CounterFactory 类的元属性,对吗?我知道这个例子可以在服务上复制(如果我错了告诉我),语义是什么这种情况下的区别? 有用的例子!因此,这基本上意味着在工厂中,您可以拥有额外的抽象层,而这些抽象层不会在服务中获得。不管返回什么,只要使用“new”,就会返回它的一个新实例。任何未在返回块内声明的变量都是单例的。我做对了吗? @Swanidhi 基本上是的,您可以在工厂中声明为单例的变量。这就是为什么我称它们为“类”变量。【参考方案7】:

对我来说,当我意识到它们都以相同的方式工作时,我得到了启示:运行某些东西一次,存储它们获得的值,然后咳出相同的存储值 strong> 当通过依赖注入引用时。

假设我们有:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

三者的区别在于:

    a 的存储值来自运行 fn ,换句话说:fn() b的存储值来自newing fn,换句话说:new fn() c的存储值来自先通过newingfn获取实例,然后运行实例的$get方法

这意味着,在 angular 内部有一个类似于缓存对象的东西,每次注入的值只分配一次,当它们第一次被注入时,以及在哪里:

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

这就是我们在服务中使用this 并在提供者中定义this.$get 的原因。

希望这会有所帮助。

【讨论】:

最后,一个理智的解释。 Angular 很疯狂,而且非常糟糕,以至于它会受伤。 这应该是公认的答案,因为它实际上回答了为什么工厂、服务和提供者返回单例值的问题。其他答案解释了工厂、服务和提供者之间的区别,但从未涉及单例方面。 我喜欢这个……当我读到其他博主的千行句子时……我只能理解工厂。但我读了这个……我明白所有 3 个。 .service.factory 都是 .provide 的快捷方式。最后所有的服务都来自于调用.$get() 所以在使用providers时必须提供$get的实现?【参考方案8】:

基本区别在于 provider 允许将原始(非对象)、数组或回调函数值设置到工厂声明的变量中,因此如果返回一个对象,则必须显式声明并返回。

另一方面,service 只能用于将服务声明的变量设置为对象,因此我们可以避免对象的显式创建和返回,而另一方面它允许this 关键字的用法。

或者简而言之“provider 是一种更通用的形式,而 service 仅限于对象”。

【讨论】:

【参考方案9】:

很简单:

.service - 注册函数将作为构造函数调用(又名“newed”)

.factory - 注册函数将作为简单函数调用

两者都被调用一次,导致一个单例对象被注入到应用程序的其他组件中。

【讨论】:

是的。我们不要让事情变得比实际更复杂【参考方案10】:

“工厂”和“服务”是 Angular 进行 DI(依赖注入)的不同方式。

所以当我们使用“服务”定义 DI 时,如下面的代码所示。这将创建“Logger”对象的新 GLOBAL 实例并将其注入到函数中。

app.service("Logger", Logger); // Injects a global object

当您使用“工厂”定义 DI 时,它不会创建实例。它只是传递方法,之后消费者必须在内部调用工厂以获取对象实例。

app.factory("Customerfactory", CreateCustomer);

下面是一张简单的图片,直观地展示了“服务”的 DI 流程与“工厂”的不同之处。

当我们想根据场景创建不同类型的对象时,应该使用工厂。例如,根据场景,我们想要创建一个简单的“客户”对象,或“客户”与“地址”对象或“客户”与“电话”对象。 Here is a detailed explanation of this paragraph

当我们需要注入实用程序或共享函数时,应该使用服务,例如 Utility 、 Logger 、 Error handler 等。

【讨论】:

我在这个问题上看到的每个答案以及类似的其他答案都在说明机制和语法上的差异。这个答案给出了一个真正的理由,为什么你会选择一个而不是另一个。这是一个语义问题,查看名称、服务或工厂,传达它们的目的以及它们的使用方式。【参考方案11】:

所有提供商的工作方式都相同。不同的方法servicefactoryprovider只是让你用更少的代码完成同样的事情。

附:还有valueconstant

provider 开始到value 结束的每个特殊情况都有一个额外的限制。所以要在它们之间做出决定,你必须问自己,哪一个可以让你用更少的代码完成你想要的。

这是一张图片,向您展示了我的意思:

您可以在我从以下位置获得这张图片的博客文章中获得细分和参考指南:

http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/

【讨论】:

服务都说是单例的,但是每次注入的时候都在创建新的实例,怎么会是单例呢? @AnkurMarwaha 不是每次都创建一个新实例,它只创建一次并由 AngularJS 缓存。无论您使用的是提供者、工厂、服务等,都是如此。您可以使用console.log() 并注入多个控制器来确认这一点。 Luis,您的评论与它所说的接受的答案相冲突——最后,重要的是要认识到所有 Angular 服务都是应用程序单例。这意味着每个注入器只有一个给定服务的实例。 @AnkurMarwaha 也许我误解了什么。您引用了“重要的是要意识到所有 Angular 服务都是应用程序单例”——它们是单例的事实意味着它们只创建一次。这就是我所说的“不是每次都创建一个新实例,它只创建一次并缓存......”。你能更详细地指出你看到冲突的地方吗? 啊,我明白了。 “注射器”是一个有角度的物体。它负责进行“注射”。例如,当控制器第一次运行时,“注入器”会查看参数并注入每个参数。您的整个应用程序只有一个“注入器”。一旦注入器创建了一个特定的工厂或服务,它就会为它保留一个实例并重用它——因此是单例。所以每个应用程序只有一个注入器,每个注入器只有一个给定服务的实例。大多数 Angular 应用程序只有一个应用程序,因此只有一个注入器,因此任何服务、控制器等都有一个实例。【参考方案12】:

Service 风格:(可能是最简单的)返回实际函数:用于共享实用函数,只需将 () 附加到注入函数即可调用参考。

AngularJS 中的服务是一个包含一组函数的单例 JavaScript 对象

var myModule = angular.module("myModule", []);

myModule.value  ("myValue"  , "12345");

function MyService(myValue) 
    this.doIt = function() 
        console.log("done: " + myValue;
    


myModule.service("myService", MyService);
myModule.controller("MyController", function($scope, myService) 

    myService.doIt();

);

Factory 风格:(更复杂但更复杂)返回函数的返回值:在 java 中实例化一个像 new Object() 这样的对象。

Factory 是一个创造价值的函数。当服务、控制器等需要从工厂注入的值时,工厂会按需创建该值。一旦创建,该值就会被所有需要注入的服务、控制器等重用。

var myModule = angular.module("myModule", []);

myModule.value("numberValue", 999);

myModule.factory("myFactory", function(numberValue) 
    return "a value: " + numberValue;
)  
myModule.controller("MyController", function($scope, myFactory) 

    console.log(myFactory);

);

Provider 风格:(完整的、可配置的版本)返回函数的 $get 函数的输出:可配置。

AngularJS 中的提供者是您可以创建的最灵活的工厂形式。您可以像使用服务或工厂一样向模块注册提供程序,但您使用 provider() 函数代替。

var myModule = angular.module("myModule", []);

myModule.provider("mySecondService", function() 
    var provider = ;
    var config   =  configParam : "default" ;

    provider.doConfig = function(configParam) 
        config.configParam = configParam;
    

    provider.$get = function() 
        var service = ;

        service.doService = function() 
            console.log("mySecondService: " + config.configParam);
        

        return service;
    

    return provider;
);

myModule.config( function( mySecondServiceProvider ) 
    mySecondServiceProvider.doConfig("new config param");
);

myModule.controller("MyController", function($scope, mySecondService) 

    $scope.whenButtonClicked = function() 
        mySecondService.doIt();
    

);

src jenkov

<!DOCTYPE html>
    <html ng-app="app">
    <head>
    	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
    	<meta charset=utf-8 />
    	<title>JS Bin</title>
    </head>
    <body ng-controller="MyCtrl">
    	serviceOutput
    	<br/><br/>
    	factoryOutput
    	<br/><br/>
    	providerOutput
    
    	<script>
    
    		var app = angular.module( 'app', [] );
    
    		var MyFunc = function() 
    
    			this.name = "default name";
    
    			this.$get = function() 
    				this.name = "new name"
    				return "Hello from MyFunc.$get(). this.name = " + this.name;
    			;
    
    			return "Hello from MyFunc(). this.name = " + this.name;
    		;
    
    		// returns the actual function
    		app.service( 'myService', MyFunc );
    
    		// returns the function's return value
    		app.factory( 'myFactory', MyFunc );
    
    		// returns the output of the function's $get function
    		app.provider( 'myProv', MyFunc );
    
    		function MyCtrl( $scope, myService, myFactory, myProv ) 
    
    			$scope.serviceOutput = "myService = " + myService;
    			$scope.factoryOutput = "myFactory = " + myFactory;
    			$scope.providerOutput = "myProvider = " + myProv;
    
    		
    
    	</script>
    
    </body>
    </html>

jsbin

<!DOCTYPE html>
<html ng-app="myApp">
<head>
	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
	<meta charset=utf-8 />
	<title>JS Bin</title>
</head>
<body>
<div ng-controller="MyCtrl">
    hellos
</div>
	<script>

	var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() 
    this.sayHello = function() 
        return "Hello, World!"
    ;
);

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() 
    return 
        sayHello: function() 
            return "Hello, World!"
        
    ;
);
    
//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() 

    this.name = 'Default';

    this.$get = function() 
        var name = this.name;
        return 
            sayHello: function() 
                return "Hello, " + name + "!"
            
        
    ;

    this.setName = function(name) 
        this.name = name;
    ;
);

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider)
    helloWorldProvider.setName('World');
);
        

function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) 
    
    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];

	</script>

</body>
</html>

jsfiddle

【讨论】:

【参考方案13】:

这就是我理解它们在设计模式方面的区别的方式:

Service:返回一个类型,该类型将被新建以创建该类型的对象。如果使用 Java 类比,Service 返回一个 Java 类定义

Factory:返回一个可以立即使用的具体对象。在 Java 类比中,工厂返回一个 Java 对象

经常让人们(包括我自己)感到困惑的部分是,当您在代码中注入服务或工厂时,它们可以以相同的方式使用,在这两种情况下,您在代码中得到的都是一个具体的对象,您可以立即调用。这意味着在服务的情况下,角度代表您在服务声明中调用“新”。我认为这是一个复杂的概念。

【讨论】:

【参考方案14】:

这将是理解 Service Vs Factory Vs Provider 的最佳简短答案

来源:https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/HuZsOsMvKv4J

bendemo 说的话http://jsbin.com/ohamub/1/edit?html,output

“代码中有 cmets 说明了主要区别,但我将在此处对其进行一些扩展。作为说明,我只是对此有所了解,所以如果我说任何错误,请告诉我。

服务

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

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

【讨论】:

【参考方案15】:

我有一段时间有这种困惑,我正在尽力在这里提供一个简单的解释。希望这会有所帮助!

angular .factoryangular .service 都用于初始化服务并以相同的方式工作。

唯一的区别是,您希望如何初始化您的服务。

都是单身人士


var app = angular.module('app', []);


工厂

app.factory(&lt;service name&gt;, &lt;function with a return value&gt;)

如果您想从具有返回值的函数初始化您的服务,您必须使用factory 方法。

例如

function myService() 
  //return what you want
  var service = 
    myfunc: function (param)  /* do stuff */ 
  
  return service;


app.factory('myService', myService);

注入此服务时(例如注入到您的控制器):

Angular 将调用您的给定函数(如myService())以返回对象 Singleton - 只调用一次,存储并传递同一个对象。


服务

app.service(&lt;service name&gt;, &lt;constructor function&gt;)

如果你想从构造函数(使用this关键字)初始化你的服务,你必须使用这个service方法。

例如

function myService() 
  this.myfunc: function (param)  /* do stuff */ 


app.service('myService', myService);

注入此服务时(例如注入到您的控制器):

Angular 将 newing 您给定的函数(如 new myService())返回对象 Singleton - 只调用一次,存储并传递同一个对象。


注意:如果您将factory&lt;constructor function&gt;service&lt;function with a return value&gt; 一起使用,它将不起作用。

示例 - 演示

Angular Service vs Factory Angular Service vs Factory (with route)

【讨论】:

【参考方案16】:

感谢 Pascal Precht 的一篇博文,这帮助我理解了其中的区别。

服务是模块上的一个方法,它接受一个名称和一个定义服务的函数。您可以在其他组件(如控制器、指令和过滤器)中注入和使用该特定服务。工厂是模块上的一种方法,它还带有一个名称和一个函数,用于定义工厂。我们也可以像使用服务一样注入和使用它。

使用 new 创建的对象使用其构造函数的原型属性的值作为原型,因此我找到了调用 Object.create() 的 Angular 代码,我相信它是实例化时的服务构造函数。然而,工厂函数实际上只是一个被调用的函数,这就是为什么我们必须为工厂返回一个对象字面量。

这是我为工厂找到的 Angular 1.5 代码:

var needsRecurse = false;
    var destination = copyType(source);

    if (destination === undefined) 
      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
      needsRecurse = true;
    

factory() 函数的 Angular 源代码 sn-p:

 function factory(name, factoryFn, enforce) 
    return provider(name, 
      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
    );
  

它接受名称和传递的工厂函数,并返回一个同名的提供者,它有一个 $get 方法,这是我们的工厂函数。每当您向注入器询问特定依赖项时,它基本上都会通过调用 $get() 方法向相应的提供者询问该服务的实例。这就是为什么在创建提供者时需要 $get() 的原因。

这是服务的 Angular 1.5 代码。

function service(name, constructor) 
    return factory(name, ['$injector', function($injector) 
      return $injector.instantiate(constructor);
    ]);
  

原来我们调用service()的时候,其实调用的是factory()!但是,它不只是将我们的服务构造函数按原样传递给工厂。它还传递了一个函数,该函数要求注入器通过给定的构造函数实例化一个对象。

换句话说,如果我们在某处注入 MyService,代码中会发生什么:

MyServiceProvider.$get(); // return the instance of the service

为了再次重申它,服务调用了一个工厂,它是对应提供者上的一个 $get() 方法。此外,$injector.instantiate() 是最终使用构造函数调用 Object.create() 的方法。这就是我们在服务中使用“this”的原因。

对于 ES5,我们使用哪个无关紧要:service() 或 factory(),它始终是一个被调用的工厂,它为我们的服务创建一个提供者。

不过,您也可以对服务执行完全相同的操作。服务是一个构造函数,但是,它不会阻止我们返回对象字面量。所以我们可以把我们的服务代码写成它基本上和我们的工厂做同样的事情,或者换句话说,你可以把服务写成工厂来返回一个对象。

为什么大多数人建议使用工厂而不是服务?这是我从 Pawel Kozlowski 的书:Mastering Web Application Development with AngularJS 中看到的最佳答案。

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

【讨论】:

【参考方案17】: 使用 factory,您实际上是在 factory 内部创建了一个 object 并将其返回。 使用服务,您只需一个标准函数,它使用 this 关键字来定义 功能。 通过 provider,您可以定义一个 $get,并且可以使用它获取返回的对象 数据。

【讨论】:

【参考方案18】:

在 AngularJS 中有三种处理业务逻辑的方法:(灵感来自 Yaakov 的 Coursera AngularJS 课程)它们是:

    服务 工厂 提供者

这里我们只讨论Service vs Factory

服务

语法:

app.js

 var app = angular.module('ServiceExample',[]);
 var serviceExampleController =
              app.controller('ServiceExampleController', ServiceExampleController);
 var serviceExample = app.service('NameOfTheService', NameOfTheService);

 ServiceExampleController.$inject = ['NameOfTheService'] //very important as this protects from minification of js files

function ServiceExampleController(NameOfTheService)
     serviceExampleController = this;
     serviceExampleController.data = NameOfTheService.getSomeData();
 

function NameOfTheService()
     nameOfTheService = this;
     nameOfTheService.data = "Some Data";
     nameOfTheService.getSomeData = function()
           return nameOfTheService.data;
          

index.html

<div ng-controller = "ServiceExampleController as serviceExample">
   serviceExample.data
</div>

服务的主要特点:

    延迟实例化:如果服务没有被注入,它将永远不会被实例化。因此,要使用它,您必须将其注入到模块中。

    Singleton:如果注入到多个模块中,所有模块都只能访问一个特定的实例。这就是为什么在不同的控制器之间共享数据非常方便。

工厂

现在我们来谈谈 AngularJS 中的工厂

首先让我们看一下语法

app.js

var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);

//first implementation where it returns a function
function NameOfTheFactoryOne()
   var factory = function()
      return new SomeService();
    
   return factory;


//second implementation where an object literal would be returned
function NameOfTheFactoryTwo()
   var factory = 
      getSomeService : function()
          return new SomeService();
       
    ;
   return factory;

现在在控制器中使用以上两个:

 var factoryOne = NameOfTheFactoryOne() //since it returns a function
 factoryOne.someMethod();

 var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
 factoryTwo.someMethod();

工厂特点:

    此类服务遵循工厂设计模式。可以将工厂视为创建新对象或方法的中心位置。

    这不仅会产生单例,还会产生可定制的服务。

    .service() 方法是一个工厂,它总是产生相同类型的服务,即单例。没有简单的方法来配置它的行为。 .service() 方法通常用作不需要任何配置的快捷方式。

【讨论】:

【参考方案19】:

简短的解释请参考https://***.com/a/26924234/5811973。

详细解释请参考https://***.com/a/15666049/5811973。

同样来自 angularJs 文档:

【讨论】:

【参考方案20】:

您可以通过这个类比来理解差异 - 考虑将返回一些值的普通函数和将使用 new 关键字实例化的构造函数之间的区别。因此创建工厂类似于创建将返回一些值的普通函数(原始或对象)而创建服务就像创建构造函数(OO 类),我们可以使用 new 关键字创建实例。唯一需要注意的是,当我们使用 Service 方法创建服务时,它会使用 AngularJS 支持的依赖注入机制自动创建它的实例

【讨论】:

以上是关于对服务与工厂感到困惑的主要内容,如果未能解决你的问题,请参考以下文章

对 PayPal 的服务器端 SDK 感到困惑

对服务器发送的事件感到困惑

对同步适配器、服务、加载程序、提供程序和异步任务感到困惑? [关闭]

对 ESB 作为点对点集成的解决方案感到困惑

对截断语句的标准定义感到困惑

对 memcache 将 AppEngine py2.7 应用程序迁移到 py3 感到困惑