搞不清服务和工厂

根据我的理解,当我在工厂中返回一个被注入到控制器的对象。在服务内部,我使用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是一个单例?

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

270109 次浏览

# EYZ0:

文档(见作为单例服务): 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 + "!";
}
}
});

看看这个关于$ provider: http://slides.wesalvaro.com/20121113/#/的演示

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

还有一种方法可以返回构造函数,这样你就可以在工厂中返回< em >再生< / em >类,就像这样:

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"),

看这里完整的例子:
# EYZ0 < / p > 这里是谷歌小组页面,在那里讨论:
# EYZ0 < / p >

补充第一个答案,我认为.service()适合那些以更面向对象的风格(c# /Java)编写代码的人(使用这个关键字并通过prototype/Constructor函数实例化对象)。

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

live example

“;Hello world”;例子

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

以下是主要的区别:

服务

语法:# EYZ0

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

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

工厂

语法:# EYZ0

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

用法:可能用于返回“类”函数,然后可以重新创建实例。

还检查AngularJS文档和stackoverflow 搞不清服务和工厂上的类似问题。

这是使用服务和工厂的示例。阅读更多关于AngularJS服务vs工厂的内容。

这里有更多的服务与工厂的例子,这些例子可能有助于了解它们之间的区别。基本上,一个服务调用了“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来创建多个计数器。我们可以访问class变量来查看创建了多少个计数器:

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

对我来说,当我意识到它们都以相同的方式工作时,我才发现:通过运行一次,存储它们得到的值,然后通过依赖注入引用时吐出相同的存储值

假设我们有:

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

这三者的区别在于:

  1. a的存储值来自于运行fn,换句话说:fn()
  2. b的存储值来自newing fn,换句话说:new fn()
  3. c的存储值来自于首先通过newing fn获得一个实例,然后运行该实例的$get方法

这意味着,在angular内部有一个类似缓存对象的东西,它的每次注入的值只被赋值一次,当它们第一次被注入时,并且在:

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

这就是为什么我们在服务中使用this,而在提供者中定义this.$get

希望这能有所帮助。

基本的区别是,提供者允许将原语(非对象)、数组或回调函数值设置到工厂声明的变量中,因此如果返回一个对象,它必须显式地声明和返回。

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

或者简单地说,“提供者是一种更通用的形式,而服务仅限于对象”。

非常简单:

.service——注册的函数将作为构造函数被调用(又名'newed')

.factory注册的函数将被作为一个简单函数调用

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

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

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

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

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

app.factory("Customerfactory", CreateCustomer);

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

enter image description here

当我们想要根据场景创建不同类型的对象时,应该使用Factory。例如,根据不同的场景,我们想要创建一个简单的“Customer”对象,或者“Address”对象中的“Customer”,或者“Phone”对象中的“Customer”。# EYZ0

当我们有实用程序或共享函数被注入,如实用程序,记录器,错误处理程序等时,应该使用服务。

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

附注:还有valueconstant

provider开始到value结束的链中的每个特殊情况都有一个额外的限制。所以要在两者之间做出选择,你必须问问自己,哪一个能让你用更少的代码完成你想要的。

下面这张图可以说明我的意思:

enter image description here

你可以在我的博客文章中找到这张照片的分类和参考指南:

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

服务样式:(可能是最简单的一个)返回实际函数:用于共享实用程序函数,只需将()附加到注入的函数引用即可调用。

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


});

工厂样式:(更复杂也更复杂)返回函数的返回值:在java中实例化一个对象,如new object()。

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

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


});

提供者样式:(完整的、可配置的版本)返回函数的$get函数的输出:可配置。

AngularJS中的Providers是你能创建的最灵活的工厂形式。向模块注册提供者就像向服务或工厂注册一样,只是使用了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

我是这样理解它们在设计模式上的区别的:

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

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

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

这将是理解服务Vs工厂Vs提供商的最佳和简短的答案

# EYZ0: # EYZ1

这里是演示 http://jsbin.com/ohamub/1/edit?html,output表示的

“代码中有一些注释说明了主要的差异,但我将在这里展开一点。作为说明,我只是在思考这个问题,所以如果我说错了什么,请告诉我。

< em > < / em >服务

# EYZ0:模块。service('serviceName',函数);

结果:当将serviceName声明为可注入参数时,将提供传递给module.service的实际函数引用。

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

< em > < / em >工厂

# EYZ0:模块。factory('factoryName',函数);

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

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

< em > < / em >提供者

# EYZ0:模块。provider('providerName',函数);

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

使用:可能用于返回一个'类'函数,然后可以重新创建实例,但在被注入之前需要某种配置。也许对跨项目可重用的类有用?这一点还不太清楚。” 本< / p >

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

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

# EYZ0

两人都是单身人士


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

<人力资源/ >

工厂

app.factory (# EYZ0, # EYZ1)

如果希望从一个有返回值的函数初始化服务,则必须使用factory方法。

如。

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


app.factory('myService', myService);

# EYZ0

  • Angular将调用作为你给定的函数(如myService())来返回对象
  • 单例 -只调用一次,存储,传递同一个对象。

<人力资源/ >

服务

app.service (# EYZ0, # EYZ1)

如果希望从构造函数(使用this关键字)初始化服务,则必须使用service方法。

如。

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


app.service('myService', myService);

# EYZ0

  • Angular将newing你给定的函数(如new myService())来返回对象
  • 单例 -只调用一次,存储,传递同一个对象。
人力资源/ > < p > < 注意:如果您使用factory<constructor function>service<function with a return value>,它将不起作用

示例- DEMOs

  • < a href = " http://plnkr.co/edit/65ErFP5rIUrfgtW93JZn?p=preview" rel="nofollow">Angular Service vs Factory
  • < a href = " http://plnkr.co/edit/910nt34d8DTISdtzLD8E?p=preview" rel="nofollow">Angular Service vs Factory(带路由) . p=preview" rel="nofollow">Angular Service vs Factory(带路由

多亏了Pascal Precht的一篇博客文章,这帮助我理解了其中的区别。

服务是模块上的一个方法,它接受定义服务的名称和函数。你可以在其他组件中注入和使用特定的服务,比如控制器、指令和过滤器。工厂是模块上的一个方法,它还接受一个定义工厂的名称和函数。我们还可以像对服务那样注入和使用it。

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

下面是我为factory找到的angular 1.5代码:

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


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

factory()函数的Angular源代码片段:

 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。

factory方法是获取对象的最常用方法 AngularJS依赖注入系统。它是非常灵活的,可以 包含复杂的创建逻辑。因为工厂是正规的 函数,也可以利用新的词法作用域来实现 模拟“私有”变量。这很有用,因为我们可以隐藏 给定服务的实现细节。" < / p >
  • 使用工厂,您实际上在工厂中创建了对象并返回它。
  • 对于服务,你只有一个使用 this关键字来定义的标准函数 李函数。< / > 在提供者中有一个你定义的$get,它可以使用返回的对象得到 李数据。< / >

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

  1. 服务
  2. 工厂
  3. 提供者

这里我们只讨论服务 vs 工厂

# EYZ0:

语法:

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>

服务的主要特点:

  1. lazy Instantiated:如果服务没有被注入,它将永远不会被实例化。所以要使用它,你必须将它注入到一个模块中。

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

工厂

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

首先让我们来看看语法:

# EYZ0:

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

工厂特点:

  1. 这种类型的服务遵循工厂设计模式。工厂可以被认为是创建新对象或方法的中心场所。

  2. 这不仅可以生成单例服务,还可以生成可定制的服务。

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

要获得简短而简单的解释,请参阅https://stackoverflow.com/a/26924234/5811973

详细解释请参阅https://stackoverflow.com/a/15666049/5811973

也来自angularJs文档: # EYZ0 < / p >

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