AngularJS中的服务、提供商和工厂之间有什么区别?
当前回答
下面是我为AngularjS中的对象工厂设计的一些烧烤代码模板。我用汽车/汽车工厂作为例子来说明。在控制器中生成简单的实现代码。
<script>
angular.module('app', [])
.factory('CarFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Car = function() {
// initialize instance properties
angular.extend(this, {
color : null,
numberOfDoors : null,
hasFancyRadio : null,
hasLeatherSeats : null
});
// generic setter (with optional default value)
this.set = function(key, value, defaultValue, allowUndefined) {
// by default,
if (typeof allowUndefined === 'undefined') {
// we don't allow setter to accept "undefined" as a value
allowUndefined = false;
}
// if we do not allow undefined values, and..
if (!allowUndefined) {
// if an undefined value was passed in
if (value === undefined) {
// and a default value was specified
if (defaultValue !== undefined) {
// use the specified default value
value = defaultValue;
} else {
// otherwise use the class.prototype.defaults value
value = this.defaults[key];
} // end if/else
} // end if
} // end if
// update
this[key] = value;
// return reference to this object (fluent)
return this;
}; // end this.set()
}; // end this.Car class definition
// instance properties default values
this.Car.prototype.defaults = {
color: 'yellow',
numberOfDoors: 2,
hasLeatherSeats: null,
hasFancyRadio: false
};
// instance factory method / constructor
this.Car.prototype.instance = function(params) {
return new
this.constructor()
.set('color', params.color)
.set('numberOfDoors', params.numberOfDoors)
.set('hasFancyRadio', params.hasFancyRadio)
.set('hasLeatherSeats', params.hasLeatherSeats)
;
};
return new this.Car();
}) // end Factory Definition
.controller('testCtrl', function($scope, CarFactory) {
window.testCtrl = $scope;
// first car, is red, uses class default for:
// numberOfDoors, and hasLeatherSeats
$scope.car1 = CarFactory
.instance({
color: 'red'
})
;
// second car, is blue, has 3 doors,
// uses class default for hasLeatherSeats
$scope.car2 = CarFactory
.instance({
color: 'blue',
numberOfDoors: 3
})
;
// third car, has 4 doors, uses class default for
// color and hasLeatherSeats
$scope.car3 = CarFactory
.instance({
numberOfDoors: 4
})
;
// sets an undefined variable for 'hasFancyRadio',
// explicitly defines "true" as default when value is undefined
$scope.hasFancyRadio = undefined;
$scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);
// fourth car, purple, 4 doors,
// uses class default for hasLeatherSeats
$scope.car4 = CarFactory
.instance({
color: 'purple',
numberOfDoors: 4
});
// and then explicitly sets hasLeatherSeats to undefined
$scope.hasLeatherSeats = undefined;
$scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);
// in console, type window.testCtrl to see the resulting objects
});
</script>
这里有一个更简单的例子。我使用的是一些第三方库,它们期望“Position”对象显示纬度和经度,但通过不同的对象财产。我不想破解供应商代码,所以我调整了我传递的“位置”对象。
angular.module('app')
.factory('PositionFactory', function() {
/**
* BroilerPlate Object Instance Factory Definition / Example
*/
this.Position = function() {
// initialize instance properties
// (multiple properties to satisfy multiple external interface contracts)
angular.extend(this, {
lat : null,
lon : null,
latitude : null,
longitude : null,
coords: {
latitude: null,
longitude: null
}
});
this.setLatitude = function(latitude) {
this.latitude = latitude;
this.lat = latitude;
this.coords.latitude = latitude;
return this;
};
this.setLongitude = function(longitude) {
this.longitude = longitude;
this.lon = longitude;
this.coords.longitude = longitude;
return this;
};
}; // end class definition
// instance factory method / constructor
this.Position.prototype.instance = function(params) {
return new
this.constructor()
.setLatitude(params.latitude)
.setLongitude(params.longitude)
;
};
return new this.Position();
}) // end Factory Definition
.controller('testCtrl', function($scope, PositionFactory) {
$scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
$scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller
;
其他回答
1.服务是在必要时创建的单例对象,在应用程序生命周期结束之前(浏览器关闭时)不会被清理。控制器在不再需要时被销毁和清理。
2.创建服务的最简单方法是使用factory()方法。factory()方法允许我们通过返回包含服务函数和服务数据的对象来定义服务。服务定义函数是我们放置可注入服务的地方,例如$http和$q。前任:
angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
// our factory definition
user: {},
setName: function(newName) {
service.user['name'] = newName;
},
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });
在我们的应用程序中使用factory()
在我们的应用程序中使用工厂很容易,因为我们可以在运行时在需要的地方简单地注入工厂。
angular.module('myApp')
.controller('MainController', function($scope, User) {
$scope.saveUser = User.save;
});
另一方面,service()方法允许我们通过定义构造函数来创建服务。我们可以使用原型对象来定义服务,而不是原始javascript对象。与factory()方法类似,我们还将在函数定义中设置可注入项。创建服务的最低级方法是使用provide()方法。这是创建可以使用.config()函数配置的服务的唯一方法。与前面的to方法不同,我们将在定义的this中设置可注射对象$get()函数定义。
正如这里的几个人正确指出的,工厂、供应商、服务,甚至价值和常量都是同一事物的版本。您可以将更通用的提供程序分解为所有这些提供程序。像这样:
这是本文的图片来源:
http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/
对我来说,理解差异的最佳和最简单的方法是:
var service, factory;
service = factory = function(injection) {}
AngularJS如何实例化特定组件(简化):
// service
var angularService = new service(injection);
// factory
var angularFactory = factory(injection);
因此,对于服务,AngularJS组件是由服务声明函数表示的类的对象实例。对于工厂,它是从工厂声明函数返回的结果。工厂的行为可能与服务相同:
var factoryAsService = function(injection) {
return new function(injection) {
// Service content
}
}
最简单的思考方式如下:
服务是一个单例对象实例。如果您想为代码提供单例对象,请使用服务。工厂是一个阶级。如果您想为代码提供自定义类,请使用工厂(无法使用服务完成,因为它们已经实例化)。
工厂“类”示例在周围的注释中提供,以及提供程序差异。
句法糖是区别。只需要提供程序。或者换句话说,只有提供者才是真正的角度,所有其他提供者都是派生的(以减少代码)。还有一个简单的版本,叫做Value(),它只返回值,不返回计算或函数。偶数值是从提供程序派生的!
那么,为什么会出现这样的并发症,为什么我们不能只使用提供者而忘记其他一切呢?它应该可以帮助我们轻松编写代码,更好地进行沟通。开玩笑的回答是,它越复杂,框架的销售就越好。
可以返回value=value的提供程序一个可以实例化并返回=工厂(+值)提供程序可以实例化+做某事=服务(+工厂,+值)提供者=必须包含名为$get(+Factory,+Service,+Value)的属性
角注入为我们得出这一结论提供了第一个线索。
$injector用于检索提供者“不是服务,不是工厂,而是提供者”定义的对象实例。
更好的答案是:Angular服务由服务工厂创建。这些服务工厂是由服务提供程序创建的函数。服务提供程序是构造函数。实例化时,它们必须包含名为$get的属性,该属性保存服务工厂函数
因此,主供应器和注入器都将就位:)。当$get可以通过从IServiceProvider继承而在提供程序中实现时,Typescript就变得有趣了。
让我们以简单的方式讨论AngularJS中处理业务逻辑的三种方法:(灵感来自Yaakov的Coursera AngularJS课程)
服务:
语法:
应用程序.js
var app = angular.module('ServiceExample',[]);
var serviceExampleController =
app.controller('ServiceExampleController', ServiceExampleController);
var serviceExample = app.service('NameOfTheService', NameOfTheService);
ServiceExampleController.$inject = ['NameOfTheService'] //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;
}
}
索引html
<div ng-controller = "ServiceExampleController as serviceExample">
{{serviceExample.data}}
</div>
服务特点:
懒惰实例化:如果它没有被注入,就永远不会被实例化。因此,要使用它,必须将其注入到模块中。Singleton:如果注入到多个模块,所有模块都只能访问一个特定的实例。这就是为什么在不同控制器之间共享数据非常方便的原因。
工厂
首先让我们看看语法:
应用.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()方法通常用作不需要任何配置的快捷方式。
供应商
让我们先来看看语法:
angular.module('ProviderModule', [])
.controller('ProviderModuleController', ProviderModuleController)
.provider('ServiceProvider', ServiceProvider)
.config(Config); //optional
Config.$inject = ['ServiceProvider'];
function Config(ServiceProvider) {
ServiceProvider.defaults.maxItems = 10; //some default value
}
ProviderModuleController.$inject = ['ServiceProvider'];
function ProviderModuleController(ServiceProvider) {
//some methods
}
function ServiceProvider() {
var provider = this;
provider.defaults = {
maxItems: 10
};
provider.$get = function () {
var someList = new someListService(provider.defaults.maxItems);
return someList;
};
}
}
提供商的特点:
Provider是在Angular中创建服务的最灵活的方法。我们不仅可以创建一个可动态配置的工厂,而且在使用工厂时,通过提供程序方法,我们可以在整个应用程序启动时自定义配置工厂一次。然后,工厂可以在整个应用程序中使用自定义设置。换句话说,我们可以在应用程序启动之前配置此工厂。事实上,在angular文档中提到,当我们使用.service或.factory方法配置服务时,提供者方法实际上是在幕后执行的。$get是一个直接附加到提供程序实例的函数。该函数是工厂函数。换句话说,它就像我们用来提供给.factory方法的一样。在该函数中,我们创建自己的服务。这个$get属性是一个函数,它使提供者成为提供者。AngularJS希望提供程序具有$get属性,该属性的值是Angular将作为工厂函数处理的函数。但使整个提供程序设置非常特殊的是,我们可以在服务提供程序内部提供一些配置对象,这通常带有默认值,我们可以稍后在步骤中覆盖这些默认值,在该步骤中我们可以配置整个应用程序。
推荐文章
- angularjs中的compile函数和link函数有什么区别
- 如何向一个5岁的孩子解释依赖注入?
- Ng-repeat结束事件
- 缓存一个HTTP 'Get'服务响应在AngularJS?
- 从ng-click获取原始元素
- Angular JS:当我们已经有了具有作用域的指令控制器时,指令的link函数还需要什么?
- Angularjs的ng-model不能在ng-if中工作
- AngularJS禁用了开发机器上的部分缓存
- 如何在AngularJS中动态添加指令?
- 如何在AngularJS中观察路由变化?
- 实例化模块失败[$injector:unpr]未知提供者:$routeProvider
- 在AngularJS中集成jQuery插件的正确方法
- 如何设置一个iframe src属性从一个变量在AngularJS
- 如何在Angular中使用$rootScope来存储变量?
- AngularJS:工厂和服务?