AngularJS의 비 싱글 톤 서비스
AngularJS는 문서에서 Services가 Singleton이라고 명시합니다.
AngularJS services are singletons
반 직관적으로 module.factory
는 Singleton 인스턴스도 반환합니다.
비 단일 서비스에 대한 많은 사용 사례가 있다는 점을 감안할 때, ExampleService
종속성이 선언 될 때마다 다른 인스턴스에 의해 충족 되도록 서비스의 인스턴스를 반환하는 팩토리 메서드를 구현하는 가장 좋은 방법 은 ExampleService
무엇입니까?
나는 new
이것이 의존성 주입을 분해하기 시작하고 라이브러리가 특히 제 3 자에게 어색하게 동작 할 것이기 때문에 공장에서 가능한 함수를 반환해야한다고 생각하지 않습니다 . 요컨대, 비단 일 서비스에 대한 합법적 인 사용 사례가 있는지 확실하지 않습니다.
동일한 작업을 수행하는 더 좋은 방법은 팩토리를 API로 사용하여 getter 및 setter 메서드가 연결된 개체 컬렉션을 반환하는 것입니다. 다음은 이러한 종류의 서비스를 사용하는 방법을 보여주는 의사 코드입니다.
.controller( 'MainCtrl', function ( $scope, widgetService ) {
$scope.onSearchFormSubmission = function () {
widgetService.findById( $scope.searchById ).then(function ( widget ) {
// this is a returned object, complete with all the getter/setters
$scope.widget = widget;
});
};
$scope.onWidgetSave = function () {
// this method persists the widget object
$scope.widget.$save();
};
});
이것은 ID로 위젯을 찾은 다음 레코드에 대한 변경 사항을 저장할 수있는 의사 코드 일뿐입니다.
다음은 서비스에 대한 의사 코드입니다.
.factory( 'widgetService', function ( $http ) {
function Widget( json ) {
angular.extend( this, json );
}
Widget.prototype = {
$save: function () {
// TODO: strip irrelevant fields
var scrubbedObject = //...
return $http.put( '/widgets/'+this.id, scrubbedObject );
}
};
function getWidgetById ( id ) {
return $http( '/widgets/'+id ).then(function ( json ) {
return new Widget( json );
});
}
// the public widget API
return {
// ...
findById: getWidgetById
// ...
};
});
이 예제에는 포함되지 않았지만 이러한 종류의 유연한 서비스는 상태를 쉽게 관리 할 수 있습니다.
지금은 시간이 없지만 도움이된다면 나중에 간단한 Plunker를 모아서 시연 할 수 있습니다.
어떤 사용 사례를 만족시키려는 지 잘 모르겠습니다. 그러나 개체의 팩토리 반환 인스턴스를 가질 수 있습니다. 필요에 맞게 수정할 수 있어야합니다.
var ExampleApplication = angular.module('ExampleApplication', []);
ExampleApplication.factory('InstancedService', function(){
function Instance(name, type){
this.name = name;
this.type = type;
}
return {
Instance: Instance
}
});
ExampleApplication.controller('InstanceController', function($scope, InstancedService){
var instanceA = new InstancedService.Instance('A','string'),
instanceB = new InstancedService.Instance('B','object');
console.log(angular.equals(instanceA, instanceB));
});
업데이트 됨
비 싱글 톤 서비스에 대한 다음 요청을 고려하십시오 . Brian Ford는 다음과 같이 말합니다.
모든 서비스가 싱글 톤이라는 생각이 새로운 객체를 인스턴스화 할 수있는 싱글 톤 팩토리를 작성하는 것을 막지는 않습니다.
공장에서 인스턴스를 반환하는 그의 예 :
myApp.factory('myService', function () {
var MyThing = function () {};
MyThing.prototype.foo = function () {};
return {
getInstance: function () {
return new MyThing();
}
};
});
나는 또한 new
컨트롤러 에서 키워드 를 사용할 필요가 없기 때문에 그의 예가 더 우수하다고 주장 합니다. getInstance
서비스 메서드 내에서 캡슐화됩니다 .
또 다른 방법은 angular.extend()
.
app.factory('Person', function(){
return {
greet: function() { return "Hello, I'm " + this.name; },
copy: function(name) { return angular.extend({name: name}, this); }
};
});
예를 들어 컨트롤러에서
app.controller('MainCtrl', function ($scope, Person) {
michael = Person.copy('Michael');
peter = Person.copy('Peter');
michael.greet(); // Hello I'm Michael
peter.greet(); // Hello I'm Peter
});
여기에 plunk가 있습니다.
이 게시물에 대한 답변은 이미 받았지만 싱글 톤이 아닌 서비스가 필요한 몇 가지 합법적 인 시나리오가있을 것이라고 생각합니다. 여러 컨트롤러간에 공유 할 수있는 재사용 가능한 비즈니스 로직이 있다고 가정 해 보겠습니다. 이 시나리오에서 로직을 배치하는 가장 좋은 장소는 서비스이지만 재사용 가능한 로직에 상태를 유지해야하는 경우 어떻게해야할까요? 그런 다음 앱의 여러 컨트롤러에서 공유 할 수 있도록 단일 서비스가 아닌 서비스가 필요합니다. 이것이 내가 이러한 서비스를 구현하는 방법입니다.
angular.module('app', [])
.factory('nonSingletonService', function(){
var instance = function (name, type){
this.name = name;
this.type = type;
return this;
}
return instance;
})
.controller('myController', ['$scope', 'nonSingletonService', function($scope, nonSingletonService){
var instanceA = new nonSingletonService('A','string');
var instanceB = new nonSingletonService('B','object');
console.log(angular.equals(instanceA, instanceB));
}]);
다음은 비 싱글 톤 서비스의 예입니다. ORM에서 작업 중입니다. 예제에서 나는 서비스 ( 'users', 'documents')가 상속하고 잠재적으로 확장하기를 원하는 기본 모델 (ModelFactory)을 보여줍니다.
내 ORM에서 ModelFactory는 모듈 시스템을 사용하여 샌드 박스 화 된 추가 기능 (쿼리, 지속성, 스키마 매핑)을 제공하기 위해 다른 서비스를 주입합니다.
이 예에서 사용자와 문서 서비스는 모두 동일한 기능을 갖지만 자체적으로 독립적 인 범위를 갖습니다.
/*
A class which which we want to have multiple instances of,
it has two attrs schema, and classname
*/
var ModelFactory;
ModelFactory = function($injector) {
this.schema = {};
this.className = "";
};
Model.prototype.klass = function() {
return {
className: this.className,
schema: this.schema
};
};
Model.prototype.register = function(className, schema) {
this.className = className;
this.schema = schema;
};
angular.module('model', []).factory('ModelFactory', [
'$injector', function($injector) {
return function() {
return $injector.instantiate(ModelFactory);
};
}
]);
/*
Creating multiple instances of ModelFactory
*/
angular.module('models', []).service('userService', [
'ModelFactory', function(modelFactory) {
var instance;
instance = new modelFactory();
instance.register("User", {
name: 'String',
username: 'String',
password: 'String',
email: 'String'
});
return instance;
}
]).service('documentService', [
'ModelFactory', function(modelFactory) {
var instance;
instance = new modelFactory();
instance.register("Document", {
name: 'String',
format: 'String',
fileSize: 'String'
});
return instance;
}
]);
/*
Example Usage
*/
angular.module('controllers', []).controller('exampleController', [
'$scope', 'userService', 'documentService', function($scope, userService, documentService) {
userService.klass();
/*
returns
{
className: "User"
schema: {
name : 'String'
username : 'String'
password: 'String'
email: 'String'
}
}
*/
return documentService.klass();
/*
returns
{
className: "User"
schema: {
name : 'String'
format : 'String'
formatileSize: 'String'
}
}
*/
}
]);
angular는 싱글 톤 서비스 / 공장 옵션 만 제공합니다 . 한 가지 방법은 컨트롤러 또는 다른 소비자 인스턴스 내부에 새 인스턴스를 빌드하는 팩토리 서비스를 사용하는 것입니다. 주입되는 유일한 것은 새 인스턴스를 만드는 클래스입니다. 다른 종속성을 주입하거나 사용자의 사양에 맞게 새 개체를 초기화 (서비스 또는 구성 추가)하기에 좋은 곳입니다.
namespace admin.factories {
'use strict';
export interface IModelFactory {
build($log: ng.ILogService, connection: string, collection: string, service: admin.services.ICollectionService): IModel;
}
class ModelFactory implements IModelFactory {
// any injection of services can happen here on the factory constructor...
// I didnt implement a constructor but you can have it contain a $log for example and save the injection from the build funtion.
build($log: ng.ILogService, connection: string, collection: string, service: admin.services.ICollectionService): IModel {
return new Model($log, connection, collection, service);
}
}
export interface IModel {
// query(connection: string, collection: string): ng.IPromise<any>;
}
class Model implements IModel {
constructor(
private $log: ng.ILogService,
private connection: string,
private collection: string,
service: admin.services.ICollectionService) {
};
}
angular.module('admin')
.service('admin.services.ModelFactory', ModelFactory);
}
그런 다음 소비자 인스턴스에서 팩토리 서비스가 필요하고 필요할 때 새 인스턴스를 가져 오기 위해 팩토리에서 빌드 메서드를 호출합니다.
class CollectionController {
public model: admin.factories.IModel;
static $inject = ['$log', '$routeParams', 'admin.services.Collection', 'admin.services.ModelFactory'];
constructor(
private $log: ng.ILogService,
$routeParams: ICollectionParams,
private service: admin.services.ICollectionService,
factory: admin.factories.IModelFactory) {
this.connection = $routeParams.connection;
this.collection = $routeParams.collection;
this.model = factory.build(this.$log, this.connection, this.collection, this.service);
}
}
you can see it provides opperatiunity to inject some specific services that are not available in the factory step. you can always have injection happen on the factory instance to be used by all Model instances.
Note I had to strip off some code so I might made some context errors... if you need a code sample that works let me know.
I believe that NG2 will have the option to inject a new instance of your service in the right place in your DOM so you dont need to build your own factory implementation. will have to wait and see :)
I believe there is good reason to create a new instance of an object within a service. We should keep an open mind as well rather than just say we ought never do such a thing, but the singleton was made that way for a reason. Controllers are created and destroyed often within the lifecycle of the app, but the services must be persistent.
I can think of a use case where you have a work flow of some kind, like accepting a payment and you have multiple properties set, but must now change their payment type because the customer's credit card failed and they need to provide a different form of payment. Of course, this does have a lot to do with the way you create your app. You could reset all properties for the payment object, or you could create a new instance of an object within the service. But, you would not want a new instance of the service, nor would you want to refresh the page.
I believe a solution is providing an object within the service that you can create a new instance of and set. But, just to be clear, the single instance of the service is important because a controller may be created and destroyed many times, but the services need persistence. What you are looking for may not be a direct method within Angular, but an object pattern that you can manage inside your service.
As an example, I have a made a reset button. (This is not tested, its really just a quick idea of a use case for creating a new object within a service.
app.controller("PaymentController", ['$scope','PaymentService',function($scope, PaymentService) {
$scope.utility = {
reset: PaymentService.payment.reset()
};
}]);
app.factory("PaymentService", ['$http', function ($http) {
var paymentURL = "https://www.paymentserviceprovider.com/servicename/token/"
function PaymentObject(){
// this.user = new User();
/** Credit Card*/
// this.paymentMethod = "";
//...
}
var payment = {
options: ["Cash", "Check", "Existing Credit Card", "New Credit Card"],
paymentMethod: new PaymentObject(),
getService: function(success, fail){
var request = $http({
method: "get",
url: paymentURL
}
);
return ( request.then(success, fail) );
}
//...
}
return {
payment: {
reset: function(){
payment.paymentMethod = new PaymentObject();
},
request: function(success, fail){
return payment.getService(success, fail)
}
}
}
}]);
Here's another approach to the problem that I was quite satisfied with, specifically when used in combination with Closure Compiler with advanced optimizations enabled:
var MyFactory = function(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
};
MyFactory.prototype.foo = function() {
console.log(this.arg1, this.arg2);
// You have static access to other injected services/factories.
console.log(MyFactory.OtherService1.foo());
console.log(MyFactory.OtherService2.foo());
};
MyFactory.factory = function(OtherService1, OtherService2) {
MyFactory.OtherService1_ = OtherService1;
MyFactory.OtherService2_ = OtherService2;
return MyFactory;
};
MyFactory.create = function(arg1, arg2) {
return new MyFactory(arg1, arg2);
};
// Using MyFactory.
MyCtrl = function(MyFactory) {
var instance = MyFactory.create('bar1', 'bar2');
instance.foo();
// Outputs "bar1", "bar2" to console, plus whatever static services do.
};
angular.module('app', [])
.factory('MyFactory', MyFactory)
.controller('MyCtrl', MyCtrl);
참고URL : https://stackoverflow.com/questions/16626075/non-singleton-services-in-angularjs
'IT story' 카테고리의 다른 글
svn cleanup : sqlite : 데이터베이스 디스크 이미지 형식이 잘못되었습니다. (0) | 2020.09.07 |
---|---|
Spring Repository 내에서 원시 SQL을 사용할 수 있습니까? (0) | 2020.09.07 |
Kotlin에서 추상 클래스의 익명 클래스 인스턴스를 만드는 방법은 무엇입니까? (0) | 2020.09.07 |
Swift에서 'get'과 'set'은 무엇입니까? (0) | 2020.09.07 |
Android SDK 관리자 용 GUI가 사라 졌습니까? (0) | 2020.09.07 |