programing

Angular에서의 비싱글톤 서비스JS

javamemo 2023. 3. 6. 20:36
반응형

Angular에서의 비싱글톤 서비스JS

AngularJs는 매뉴얼에 서비스가 싱글톤이라고 명시되어 있습니다.

AngularJS services are singletons

으로 말하면, 설적 counter counter counter counter counter counter counter 。module.factory또한 싱글톤 인스턴스도 반환합니다.

서비스에는 좋은 입니까?ExampleService됩니다.ExampleService

어떤 사용 사례를 만족시키려는지 잘 모르겠습니다.그러나 객체의 인스턴스를 공장에서 반환할 수 있습니다.필요에 따라 수정할 수 있어야 합니다.

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

});

JsFiddle

갱신필

비싱글톤 서비스에 대해서는 다음 요구를 고려해 주십시오.Brian Ford는 다음과 같이 말합니다.

모든 서비스가 싱글톤이라는 생각은 새로운 오브젝트를 인스턴스화할 수 있는 싱글톤 팩토리를 쓰는 것을 막지는 않습니다.

공장에서 사례를 반환하는 예를 들어 다음과 같습니다.

myApp.factory('myService', function () {
  var MyThing = function () {};
  MyThing.prototype.foo = function () {};
  return {
    getInstance: function () {
      return new MyThing();
    }
  };
});

, 저는 그의 합니다. '아주 좋다'를 입니다.new키워드를 지정합니다.은 is은 the, the the the the the the the the the에 캡슐화되어 .getInstance서비스 방식

것 .new이것이 의존성 주입을 분해하기 시작하고 라이브러리는 특히 서드파티에 대해 어색하게 동작합니다.즉, 싱글톤이 아닌 서비스에 대한 정당한 사용 사례가 있는지 잘 모르겠습니다.

동일한 작업을 수행하는 더 좋은 방법은 팩토리를 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
    // ...
  };
});

이 예에는 포함되지 않지만 이러한 종류의 유연한 서비스는 상태를 쉽게 관리할 수 있습니다.


지금은 시간이 없지만 도움이 된다면 나중에 간단한 플런커를 조립해서 시연해 보겠습니다.

하나의 은 서비스 입니다.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
});

여기 플렁크가 있어요.

이 투고는 이미 답변이 끝난 것으로 알고 있습니다만, 싱글톤이 아닌 서비스를 받을 필요가 있는 정당한 시나리오가 있다고 생각합니다.여러 컨트롤러 간에 공유할 수 있는 재사용 가능한 비즈니스 로직이 있다고 가정해 보겠습니다.이 시나리오에서는 논리를 도입하는 최적의 장소가 서비스입니다만, 재사용 가능한 논리로 상태를 유지할 필요가 있는 경우는 어떻게 해야 할까요?그리고 앱의 다른 컨트롤러 간에 공유할 수 있도록 싱글톤이 아닌 서비스가 필요합니다.이러한 서비스를 실장하는 방법은 다음과 같습니다.

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

  }

공장 출하 단계에서 사용할 수 없는 특정 서비스를 주입할 수 있습니다.공장 인스턴스에서 항상 주입을 수행하여 모든 모델 인스턴스에서 사용할 수 있습니다.

몇 가지 코드를 삭제해야 해서 컨텍스트 오류를 범했을 수도 있고...작동 가능한 코드 샘플이 필요하시면 알려주세요.

NG2는 DOM의 적절한 위치에 새로운 서비스 인스턴스를 삽입할 수 있는 옵션이 있다고 생각합니다.따라서, 독자적인 공장 실장을 구축할 필요는 없습니다.는 상황을 지켜봐야 합니다.)

서비스 내에서 객체의 새 인스턴스를 생성할 충분한 이유가 있다고 생각합니다.우리는 결코 그런 일을 해서는 안 된다고 말할 것이 아니라 열린 마음을 가져야 하지만, 독신자가 그렇게 된 데는 이유가 있다.컨트롤러는 앱의 라이프 사이클 내에서 생성 및 파기되는 경우가 많지만 서비스는 영속적이어야 합니다.

지불을 받아들이는 등 작업 흐름이나 여러 속성이 설정되어 있지만, 고객의 신용카드가 고장나 다른 지불 방법을 제공해야 하기 때문에 지불 유형을 변경해야 하는 사용 사례를 생각할 수 있습니다.물론 이는 앱을 만드는 방법과 많은 관련이 있습니다.결제 개체의 모든 속성을 재설정하거나 서비스 내에 개체의 새 인스턴스를 생성할 수 있습니다.그러나 서비스의 새 인스턴스를 원하지 않으며 페이지를 새로 고치는 것도 원하지 않습니다.

솔루션이란 서비스 내에서 새로운 인스턴스를 생성하여 설정할 수 있는 객체를 제공하는 것이라고 생각합니다.단, 컨트롤러는 여러 번 생성 및 파괴될 수 있지만 서비스는 지속성이 필요하기 때문에 서비스의 단일 인스턴스가 중요합니다.원하는 것은 Angular 내에서 직접 메서드가 아니라 서비스 내에서 관리할 수 있는 객체 패턴일 수 있습니다.

예를 들어 리셋 버튼을 만들었습니다.(이것은 테스트된 것이 아닙니다.서비스 내에서 새로운 오브젝트를 작성하기 위한 간단한 사용 예에 불과합니다.

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

다음은 특히 Closure 컴파일러와 함께 고급 최적화가 활성화된 상태에서 사용할 때 매우 만족했던 문제에 대한 다른 접근 방법입니다.

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

반응형