앵귤러 서비스 vs 앵귤러 팩토리


1065

서비스를 선언하는 데 사용되는 angular.factory ()angular.service ()를 모두 보았습니다 . 그러나 공식 문서의 어느 곳도 찾을 수 없습니다 angular.service .

두 방법의 차이점은 무엇입니까?
무엇을 사용해야합니까 (다른 일을한다고 가정)?



4
"[angularjs] 서비스 팩토리"를 검색했지만 이미 질문이 있다는 것을 기억하고있었습니다.
Mark Rajcok

2
검색에서 대괄호는 태그를 의미합니까?
jacob

11
@Jacob 대괄호로 검색 범위를 좁 힙니다. [angularjs] 지시문-angularjs로 이미 태그 된 질문에 대한 '지시문'을 검색합니다.
Mahbub

1
@Mahbub 즉, "yes":)
Brian

답변:


1268
  angular.service('myService', myServiceFunction);
  angular.factory('myFactory', myFactoryFunction);

이런 식으로 머리를 감쌀 때까지이 개념을 머리에 감쌀 수 없었습니다.

서비스 : 작성하는 기능새로운 기능 입니다 .

  myInjectedService  <----  new myServiceFunction()

팩토리 : 작성한 함수 (생성자)가 호출됩니다 .

  myInjectedFactory  <---  myFactoryFunction()

당신이하는 일은 당신에게 달려 있지만 유용한 패턴이 있습니다 ...

퍼블릭 API를 공개하기 위한 서비스 함수 작성과 같은 :

function myServiceFunction() {
  this.awesomeApi = function(optional) {
    // calculate some stuff
    return awesomeListOfValues;
  }
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.awesome = myInjectedService.awesomeApi();

또는 팩토리 함수를 사용하여 공개 API를 노출하십시오.

function myFactoryFunction() {
  var aPrivateVariable = "yay";

  function hello() {
    return "hello mars " + aPrivateVariable;
  }

  // expose a public API
  return {
    hello: hello
  };
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.hello = myInjectedFactory.hello();

또는 팩토리 함수를 사용하여 생성자를 반환합니다.

function myFactoryFunction() {
    return function() {
        var a = 2;
        this.a2 = function() {
            return a*2;
        };
    };
}
---------------------------------------------------------------------------------
// Injected in your controller
var myShinyNewObject = new myInjectedFactory();
$scope.four = myShinyNewObject.a2();

어느 것을 사용해야합니까? ...

둘 다 같은 것을 달성 할 수 있습니다. 그러나 어떤 경우에는 공장 에서 더 간단한 구문으로 주사제를 만들 수있는 약간의 유연성을 제공합니다. myInjectedService는 항상 객체 여야하지만 myInjectedFactory는 객체, 함수 참조 또는 모든 값일 수 있기 때문입니다. 예를 들어 생성자를 만드는 서비스를 작성한 경우 (위의 마지막 예에서와 같이) 다음과 같이 인스턴스화해야합니다.

var myShinyNewObject = new myInjectedService.myFunction()

이것은 이것보다 덜 바람직하지 않습니다.

var myShinyNewObject = new myInjectedFactory();

(하지만 컨트롤러의 새로운 객체는 테스트하기가 까다로워 추적하기 어려운 종속성을 생성 하기 때문에 이러한 유형의 패턴을 처음 사용하는 것에주의해야합니다 . 당신은 new()wily-nilly를 사용하는 것보다 .)


한 가지 더, 그들은 모두 싱글 톤입니다 ...

또한 두 경우 모두 앵귤러는 싱글 톤을 관리하는 데 도움이됩니다. 서비스 또는 기능을 어디에 또는 몇 번 주입했는지에 관계없이 동일한 객체 또는 기능에 대한 동일한 참조를 얻게됩니다. (공장에서 단순히 숫자 나 문자열과 같은 값을 반환하는 경우를 제외하고는 항상 같은 값을 얻을 수 있지만 참조는 아닙니다.)


2
Newable보다 객체 생성자로 부르는 것이 낫습니까?
marksyzm

2
@ Hugo, 나는 당신이 둘 다 똑같은 일을 효과적으로 수행 할 수 있음을 보여주었습니다. 구문이 다를뿐입니다.
길 버먼

105
나는 내가 전에 서비스 및 공장의 차이점에 대해 읽어해야합니다 얼마나 많은 시간을 모르겠어요 I 해요 둘 다 필요하다 확신
DMAC 파괴자

10
우리는 이미 "새로운"이라는 동사를 가지고 있습니다. 참고로 :)
sscarduzio

7
팩토리는 호출 된 함수이므로 아무 것도 반환 할 수 있습니다. 반면에 서비스는 각도를 통해 인스턴스화 new fn()되므로 인스턴스를 반환해야합니다.
Gil Birman

318

간단히 말해서 ..

// Service
service = (a, b) => {
  a.lastName = b;
  return a;
};

// Factory
factory = (a, b) => Object.assign({}, a, { lastName: b });

const fullName = { firstName: 'john' };

// Service
const lastNameService = (a, b) => {
  a.lastName = b;
  return a;
};
console.log(lastNameService(fullName, 'doe'));

// Factory
const lastNameFactory = (a, b) => 
  Object.assign({}, a, { lastName: b })
console.log(lastNameFactory(fullName, 'doe'));


169
야, 고마워 다른 답변의 세부 사항은 유효하지 않지만 때로는 10 초 버전이 필요합니다.
R Claven

4
서비스 함수가 ​​아무것도 반환하지 않도록하십시오. this.name은 = ... 그것이 API를 노출되는 것을 보여 충분하다.
pixelbits

3
그러나 반환하고 반대하면이 대신 사용합니다. jsfiddle.net/Ne5P8/1221
MrB

@MrB, 이것은 Angular 또는이 질문의 맥락과 관련이없는 일반적인 JavaScript 기능입니다.
Om Shankar

@Om Shankar, 위의 대답은이 객체와 반환 된 객체의 차이점이 다르다는 것을 보여줍니다. 나는 "THIS"가 서비스와 함께 사용될 기본값이라는 것을 보여 주었지만 값을 반환하면 공장과 거의 동일하게 작동합니다. 그러나 반대로 공장에서는 반환 값을 요구하는 것으로 보이며 그렇지 않으면 오류가 발생합니다 (이 예에서는 jsfiddle.net/hmoc0q3v/1 ).
MrB

247

주요 차이점은 다음과 같습니다.

서비스

통사론: module.service( 'serviceName', function );

결과 : serviceName을 주사 가능한 인수로 선언하면에 전달 된 함수인스턴스 가 제공 됩니다 module.service.

사용법 : 주입 된 함수 참조 에 간단히 추가 하여 호출하는 데 유용한 유틸리티 함수공유하는 데 유용 할 수 있습니다 ( ). 함께 injectedArg.call( this )또는 유사 하게 실행할 수 있습니다 .

공장

통사론: module.factory( 'factoryName', function );

결과 : factoryName을 주입 가능한 인수로 선언하면에 전달 된 함수 참조를 호출하여 리턴되는 값이 제공 됩니다 module.factory.

사용법 : 인스턴스를 만들기 위해 새로 만들 수 있는 '클래스' 기능 을 반환하는 데 유용 할 수 있습니다 .

다음은 services 및 factory를 사용하는 예 입니다. AngularJS Service vs Factory 에 대해 자세히 알아보십시오 .

서비스 대 팩토리에 대해 혼란스러워 하는 Stackoverflow에 대한 AngularJS 문서 및 유사한 질문을 확인할 수도 있습니다 .


27
나는 당신의 공장 사용법에 동의하지 않습니다. 서비스와 팩토리 둘 다 (함수가 리턴된다고 가정하면 값이나 오브젝트 일 수 있음)를 새로 작성할 수 있습니다. 실제로 서비스는 함수 인스턴스가 제공 될 때 새로운 기능을 보장하는 유일한 옵션입니다. SERVICE 대신 FACTORY를 사용하면 서비스의 모든 속성이 본질적으로 노출되는 반면 개인 및 공용 속성에 대한 액세스를 제어 할 수 있다는 이점이 있습니다. 그리고 공급자를 공장의 공장으로 생각합니다. 구성 시간에 주사 가능하고 구성 할 수 있습니다.
Drew R

1
@DrewR 귀하의 의견에 감사드립니다. Factory를 사용하여 공개 및 개인 메소드의 좋은 예를 찾았습니다. stackoverflow.com/a/14904891/65025
edzillion

사실 이것에 대해 @DrewR에 동의해야합니다. 전에 팩토리를 사용하여 객체를 반환했지만 정직하게는 $providers항상 사용 하는 것이 좋습니다.
jedd.ahyoung

서비스가 생성자를 자동으로 인스턴스화하고 있습니까?
Martian2049

1
@DrewR-내 이해에서, 공장에서 할 수있는 것처럼 서비스에서 동일한 새로운 효과를 얻을 수 있다는 것이 사실이지만 그것이 의도 한 것이 아닙니다. 주요 목표는 유틸리티 객체를 반환하려고 할 때 더 적합한 구문을 제공한다는 것 this.myFunc = function(){}입니다. 서비스에서 간단히 작성할 수 있습니다 (코드를 작성하지 않아도 팩토리와 관련하여 객체를 생성 할 수 있습니다) ).
BornToCode

137

TL; DR

1) 당신이 사용하고있는 공장을 객체를 만든 다음 같은 개체를 반환, 그것에 속성을 추가 할 수 있습니다. 이 팩토리를 컨트롤러에 전달하면 이제 해당 컨트롤러에서 팩토리를 통해 객체의 해당 속성을 사용할 수 있습니다.

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.artist = myFactory.getArtist();
});

app.factory('myFactory', function(){
  var _artist = 'Shakira';
  var service = {};

  service.getArtist = function(){
    return _artist;
  }

  return service;
});


2) Service를 사용할 때 Angular는 'new'키워드를 사용하여 장면 뒤에서 인스턴스화합니다. 이 때문에 'this'에 속성을 추가하면 서비스는 'this'를 반환합니다. 서비스를 컨트롤러로 전달하면 이제 'this'에 대한 해당 속성을 서비스를 통해 해당 컨트롤러에서 사용할 수 있습니다.

app.controller('myServiceCtrl', function($scope, myService){
  $scope.artist = myService.getArtist();
});

app.service('myService', function(){
  var _artist = 'Nelly';
  this.getArtist = function(){
    return _artist;
  }
});



비 TL; DR

1) 팩토리
팩토리는 서비스를 생성하고 구성하는 가장 보편적 인 방법입니다. TL; DR이 말한 것보다 훨씬 많지는 않습니다. 객체를 생성하고 속성을 추가 한 다음 동일한 객체를 반환하면됩니다. 그런 다음 팩토리를 컨트롤러로 전달하면 이제 해당 컨트롤러의 팩토리를 통해 객체의 해당 속성을 사용할 수 있습니다. 보다 광범위한 예는 다음과 같습니다.

app.factory('myFactory', function(){
  var service = {};
  return service;
});

이제 'myFactory'를 컨트롤러에 전달하면 'service'에 첨부 한 모든 속성을 사용할 수 있습니다.

이제 콜백 함수에 '비공개'변수를 추가하겠습니다. 이것들은 컨트롤러에서 직접 액세스 할 수는 없지만 결국 'service'에서 getter / setter 메소드를 설정하여 필요할 때 이러한 'private'변수를 변경할 수 있습니다.

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
   _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK';
    return _finalUrl
  }

  return service;
});

여기서는 변수 / 함수를 'service'에 첨부하지 않습니다. 나중에 사용하거나 수정하기 위해 단순히 만들었습니다.

  • baseUrl은 iTunes API에 필요한 기본 URL입니다
  • _artist는 조회하고자하는 아티스트입니다.
  • _finalUrl은 iTunes를 호출 할 최종 완성 된 URL이며, makeUrl은 iTunes 친화적 인 URL을 생성하고 반환하는 기능입니다.

헬퍼 / 프라이빗 변수와 함수가 준비되었으므로 'service'객체에 속성을 추가해 봅시다. 우리가 '서비스'를 무엇이든, 우리는 'myFactory'를 전달하는 컨트롤러에서 직접 사용할 수 있습니다.

아티스트를 반환하거나 설정하는 setArtist 및 getArtist 메소드를 작성하려고합니다. 또한 생성 된 URL을 사용하여 iTunes API를 호출하는 메소드를 작성하려고합니다. 이 방법은 일단 데이터가 iTunes API에서 돌아 오면 이행 할 것을 약속합니다. Angular에서 약속을 사용한 경험이 많지 않은 경우 약속을 자세히 살펴 보는 것이 좋습니다.

아래 setArtist 는 아티스트를 허용하며 아티스트를 설정할 수 있습니다. getArtist 는 $ http 요청에 사용할 URL을 만들기 위해 아티스트 callItunes에서 makeUrl ()을 호출합니다. 그런 다음 promise 객체를 설정하고 최종 URL로 $ http 요청을 한 다음 $ http는 promise를 반환하므로 요청 후 .success 또는 .error를 호출 할 수 있습니다. 그런 다음 iTunes 데이터로 약속을 해결하거나 '오류가 발생했습니다'라는 메시지와 함께 거부합니다.

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  service.setArtist = function(artist){
    _artist = artist;
  }

  service.getArtist = function(){
    return _artist;
  }

  service.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

  return service;
});

이제 우리 공장은 완성되었습니다. 이제 모든 컨트롤러에 'myFactory'를 삽입 할 수 있으며 서비스 객체 (setArtist, getArtist 및 callItunes)에 첨부 한 메소드를 호출 할 수 있습니다.

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.data = {};
  $scope.updateArtist = function(){
    myFactory.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myFactory.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

위의 컨트롤러에서 우리는 'myFactory'서비스에 주입하고 있습니다. 그런 다음 'myFactory'의 데이터에서 나오는 $ scope 객체의 속성을 설정합니다. 위의 유일한 까다로운 코드는 이전에 약속을 다루지 않은 경우입니다. callItunes가 약속을 반환하므로 .then () 메서드를 사용하고 iTunes 데이터로 약속이 이행 된 후에 만 ​​$ scope.data.artistData를 설정할 수 있습니다. 컨트롤러가 매우 얇다는 것을 알 수 있습니다. 모든 논리 및 영구 데이터는 컨트롤러가 아닌 서비스에 있습니다.

2) 서비스
아마도 서비스 생성을 처리 할 때 알아야 할 가장 큰 것은 '새로운'키워드로 인스턴스화된다는 것입니다. JavaScript 전문가에게는 이것이 코드의 특성에 대한 큰 힌트를 제공해야합니다. JavaScript에 대한 배경 지식이 제한적인 사용자 또는 'new'키워드의 실제 기능에 익숙하지 않은 사용자를 위해 서비스의 본질을 이해하는 데 도움이되는 JavaScript 기본 사항을 검토하겠습니다.

'new'키워드로 함수를 호출 할 때 발생하는 변경 사항을 실제로 보려면 함수를 작성하고 'new'키워드로 호출 한 다음 'new'키워드를 볼 때 인터프리터가 수행하는 작업을 보여 드리겠습니다. 최종 결과는 동일합니다.

먼저 생성자를 만들어 봅시다.

var Person = function(name, age){
  this.name = name;
  this.age = age;
}

일반적인 JavaScript 생성자 함수입니다. 이제 'new'키워드를 사용하여 Person 함수를 호출 할 때마다 'this'는 새로 작성된 오브젝트에 바인드됩니다.

이제 Person의 프로토 타입에 메소드를 추가하여 Person '클래스'의 모든 인스턴스에서 사용할 수 있습니다.

Person.prototype.sayName = function(){
  alert('My name is ' + this.name);
}

이제 프로토 타입에 sayName 함수를 추가 했으므로 Person의 모든 인스턴스는 해당 인스턴스 이름을 알리기 위해 sayName 함수를 호출 할 수 있습니다.

이제 Person 생성자 함수와 프로토 타입에 sayName 함수가 있으므로 Person 인스턴스를 만든 다음 sayName 함수를 호출 해 보겠습니다.

var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'

따라서 Person 생성자를 생성하고 프로토 타입에 함수를 추가하고 Person 인스턴스를 생성 한 다음 프로토 타입에서 함수를 호출하는 코드는 다음과 같습니다.

var Person = function(name, age){
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  alert('My name is ' + this.name);
}
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'

이제 JavaScript에서 'new'키워드를 사용할 때 실제로 어떤 일이 발생하는지 살펴 보겠습니다. 첫 번째로 주목해야 할 것은 예제에서 'new'를 사용한 후에는 마치 'tyler'에서 객체 인 것처럼 메소드 (sayName)를 호출 할 수 있다는 것입니다. 그 이유 때문입니다. 먼저, Person 생성자가 코드에서 볼 수 있는지 여부에 관계없이 Person 생성자가 객체를 반환한다는 것을 알고 있습니다. 둘째, sayName 함수는 Person 인스턴스가 아닌 프로토 타입에 있으므로 Person 함수가 반환하는 객체는 실패한 조회에서 프로토 타입에 위임되어야합니다. 더 간단한 용어로, tyler.sayName ()을 호출하면 인터프리터는“OK, 방금 만든 'tyler'객체를보고 sayName 함수를 찾은 다음 호출합니다. 잠깐만 요, 여기 보이지 않습니다-내가 볼 수있는 것은 이름과 나이, 프로토 타입을 확인하겠습니다. 예, 프로토 타입에있는 것 같습니다.”라고 말합니다.

아래는 JavaScript에서 'new'키워드가 실제로하는 일에 대해 어떻게 생각할 수 있는지에 대한 코드입니다. 기본적으로 위 단락의 코드 예입니다. 나는 '인터프리터 뷰'또는 인터프리터가 코드 내부의 코드를 보는 방식을 넣었습니다.

var Person = function(name, age){
  //The line below this creates an obj object that will delegate to the person's prototype on failed lookups.
  //var obj = Object.create(Person.prototype);

  //The line directly below this sets 'this' to the newly created object
  //this = obj;

  this.name = name;
  this.age = age;

  //return this;
}

이제 'new'키워드가 JavaScript에서 실제로하는 일에 대한 지식이 있으면 Angular에서 서비스를 작성하는 것이 이해하기 쉬워야합니다.

서비스를 만들 때 이해해야 할 가장 큰 것은 서비스가 'new'키워드로 인스턴스화된다는 것입니다. 위의 예제와 그 지식을 결합하여 이제 속성과 메소드를 'this'에 직접 첨부하여 서비스 자체에서 반환한다는 것을 인식해야합니다. 이것을 실제로 살펴 봅시다.

우리가 팩토리 예제로 원래했던 것과는 달리, 우리는 객체를 생성 할 필요가 없습니다. 이전에 여러 번 언급했듯이 인터프리터가 해당 객체를 생성하고 위임 할 수 있도록 'new'키워드를 사용했기 때문입니다. 그것은 프로토 타입이고, 우리가 작업을하지 않아도 우리를 위해 그것을 돌려줍니다.

먼저, '비공개'및 도우미 기능을 만들어 봅시다. 우리가 공장과 똑같은 일을했기 때문에 이것은 매우 친숙하게 보일 것입니다. 팩토리 예제에서 각 라인이 무엇을하는지 설명하지 않겠습니다. 혼란 스러우면 팩토리 예제를 다시 읽으십시오.

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
});

이제 컨트롤러에서 사용할 수있는 모든 메소드를 'this'에 첨부하겠습니다.

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.setArtist = function(artist){
    _artist = artist;
  }

  this.getArtist = function(){
    return _artist;
  }

  this.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

});

이제 팩토리 에서처럼 setArtist, getArtist 및 callItunes는 myService를 전달하는 컨트롤러에서 사용할 수 있습니다. 다음은 myService 컨트롤러입니다 (공장 컨트롤러와 거의 동일).

app.controller('myServiceCtrl', function($scope, myService){
  $scope.data = {};
  $scope.updateArtist = function(){
    myService.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myService.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

앞에서 언급했듯이 '새로운'기능을 실제로 이해하면 서비스는 Angular의 공장과 거의 동일합니다.


12
블로그에 직접 링크를 제공 할 수 있습니다. tylermcginnis.com/angularjs-factory-vs-service-vs-provider 나는 조금 더 읽기 쉽다는 것을 알았습니다.
Tyler Collier

3
여기서 블로그를 반복해도 문제는 없지만 그레타 블로그 게시물이라는 데 동의합니다.
R Claven

5
각 직원이 수행하는 작업에 대한 자세한 설명은 있지만 공장에서 서비스를 사용하기로 선택한 이유와시기는 아직 명확하지 않습니다. 다시 말해, 언제 새로운 팩토리와 팩토리가 반환 한 객체를 선호 할 것입니까? 이것이 가장 큰 혼란이라고 생각합니다.
demisx

2
기본적으로 일정한 연결 (연결 상태, 통화 기록, 데이터 저장 장치)이있는 예에서 언급 한 iTunes API와 같이 원격 서비스에 대한 지속적인 연결을 만들려면 Factory를 사용하면됩니다. 서비스로 구현하면 API에서 무언가를 원할 때마다 연결을 다시 만들고 실제로 아무것도 저장할 수 없습니다. 서비스를 다시 만들 때마다 빈 / 기본 개체가 나타납니다.
Meki

4
나는 그것이 옳지 않다고 생각합니다, @Aznim. 다른 사람들이 말했듯이, 둘 다 싱글 톤을 제공합니다.
Cryptovirus

35

실마리는 이름에있다

서비스와 공장은 서로 비슷합니다. 둘 다 다른 객체에 주입 할 수있는 단일 객체를 생성하므로 종종 상호 교환 적으로 사용됩니다.

그것들은 다른 디자인 패턴을 구현하기 위해 의미 적으로 사용되도록 고안되었습니다.

서비스는 서비스 패턴을 구현하기위한 것입니다

서비스 패턴은 애플리케이션이 논리적으로 일관된 기능 단위로 분리되는 패턴입니다. 예를 들어 API 접근 자 또는 일련의 비즈니스 논리가 있습니다.

Angular 모델은 일반적으로 서버에서 가져온 JSON 객체이므로 비즈니스 로직을 넣을 곳이 필요하기 때문에 Angular에서 특히 중요합니다.

예를 들어 Github 서비스는 다음과 같습니다. Github과 대화하는 방법을 알고 있습니다. URL과 메소드에 대해 알고 있습니다. 컨트롤러에 삽입하면 약속을 생성하고 반환합니다.

(function() {
  var base = "https://api.github.com";

  angular.module('github', [])
    .service('githubService', function( $http ) {
      this.getEvents: function() {
        var url = [
          base,
          '/events',
          '?callback=JSON_CALLBACK'
        ].join('');
        return $http.jsonp(url);
      }
    });
  )();

공장은 공장 패턴을 구현

한편, 공장은 공장 패턴을 구현하기위한 것이다. 팩토리 함수를 사용하여 객체를 생성하는 팩토리 패턴입니다. 일반적으로 모델을 빌드하는 데 사용할 수 있습니다. 다음은 Author 생성자를 반환하는 팩토리입니다.

angular.module('user', [])
  .factory('User', function($resource) {
    var url = 'http://simple-api.herokuapp.com/api/v1/authors/:id'
    return $resource(url);
  })

우리는 이것을 다음과 같이 사용할 것입니다 :

angular.module('app', ['user'])
  .controller('authorController', function($scope, User) {
    $scope.user = new User();
  })

팩토리는 싱글 톤도 반환합니다.

공장은 생성자를 반환 할 수 있습니다

팩토리는 단순히 객체를 반환하기 때문에 위에서 본 것처럼 생성자 함수를 포함하여 원하는 모든 유형의 객체를 반환 할 수 있습니다.

공장은 개체를 반환합니다. 새로운 서비스

또 다른 기술적 차이점은 서비스와 공장 구성 방식에 있습니다. 객체를 생성하기 위해 서비스 기능이 새로워집니다. 팩토리 함수가 호출되어 객체를 반환합니다.

  • 서비스는 새로운 생성자입니다.
  • 팩토리는 단순히 호출되어 객체를 반환합니다.

즉, 서비스에서 생성자 컨텍스트에서 생성중인 객체를 가리키는 "this"에 추가합니다.

이를 설명하기 위해 다음은 서비스와 팩토리를 사용하여 만든 동일한 간단한 객체입니다.

angular.module('app', [])
  .service('helloService', function() {
    this.sayHello = function() {
      return "Hello!";
    }
  })
  .factory('helloFactory', function() {
    return {
      sayHello: function() {
        return "Hello!";
      }
    }
  });

2
좋은 설명 감사합니다! 또한 인젝터 매개 변수가 있어야 하는 팩토리 샘플 코드 의 유형 Author이 있습니다 Person.
mikhail-t

@ mik-T 덕분에 오타를 수정했습니다.
superluminary

1
서비스 패턴 사용이 올바르지 않습니다. 이것은 공장 출하 시여 야합니다. .service () 대신 .factory ()를 호출하면 정확히 동일하게 작동한다는 것을 알 수 있습니다. 서비스 패턴에는 새 객체를 반환하는 함수가 아닌 생성자 함수가 제공됩니다. 생성자 함수에서 각도 (효과적으로)는 "new"를 호출합니다. 서비스가 작동하는 유일한 이유는 객체를 반환하는 생성자 함수에서 "new"를 호출하면 실제로 생성 된 객체가 아니라 반환 된 객체를 다시 얻는 것입니다. 그리고 팩토리는 모델뿐만 아니라 원하는 것을 만들 때 사용할 수 있습니다.
Dan King

27

여기에있는 모든 대답은 서비스 및 공장 주변에있는 것으로 보이며 그것이 요청 된 이후 유효합니다. 그러나 거기를 포함한 여러 다른 사람들이 있다는 사실을 숙지하는 것도 중요합니다 provider(), value()하고 constant().

기억해야 할 열쇠는 각각이 서로의 특별한 경우라는 것입니다. 각각의 특수한 사례는 적은 코드로 동일한 작업을 수행 할 수 있도록합니다. 각각에는 추가 제한이 있습니다.

어느 것을 사용할지 결정하려면 적은 코드로 원하는 것을 할 수있는 것을 볼 수 있습니다. 다음은 이미지가 얼마나 유사한 지 보여주는 이미지입니다.

여기에 이미지 설명을 입력하십시오

단계별 사용법 및 각 사용시기에 대한 빠른 참조를 위해이 이미지를 가져온 블로그 게시물을 방문 할 수 있습니다.

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


3
@jacob는 아마도 그렇게 할 것입니다.하지만 각각을 사용할 때의 전반적인 개념뿐만 아니라 본질적으로 동일한 것의 변형이라고 생각합니다.
Luis Perez

1
@LuisPerez 블로그 링크 및 블로그의 차이점을 설명하는 비디오. 비디오에서 이러한 예를 이해하는 것이 더 쉽습니다. :)
Alin Ciocan

24

app.factory ( 'fn', fn) vs. app.service ( 'fn', fn)

구성

팩토리를 사용하면 Angular는 함수를 호출하여 결과를 얻습니다. 캐시되고 주입 된 결과입니다.

 //factory
 var obj = fn();
 return obj;

서비스를 통해 Angular는 new를 호출하여 생성자 함수를 호출 합니다. 생성 된 함수는 캐시되어 주입됩니다.

  //service
  var obj = new fn();
  return obj;

이행

반환 값 컨트롤러, 실행 블록, 지시문 등에 주입되는 것이기 때문에 일반적으로 팩토리는 오브젝트 리터럴을 리턴합니다.

  app.factory('fn', function(){
         var foo = 0;
         var bar = 0;
         function setFoo(val) {
               foo = val;
         }
         function setBar (val){
               bar = val;
         }
         return {
                setFoo: setFoo,
                serBar: setBar
         }
  });

서비스 기능은 일반적으로 아무것도 반환하지 않습니다. 대신, 초기화 및 노출 기능을 수행합니다. 함수는 'new'를 사용하여 생성되었으므로 'this'를 참조 할 수도 있습니다.

app.service('fn', function () {
         var foo = 0;
         var bar = 0;
         this.setFoo = function (val) {
               foo = val;
         }
         this.setBar = function (val){
               bar = val;
         }
});

결론

팩토리 나 서비스를 사용하는 경우에는 둘 다 매우 유사합니다. 그것들은 컨트롤러, 지시어, 실행 블록 등에 주입되며 클라이언트 코드에서 거의 같은 방식으로 사용됩니다. 또한 둘 다 싱글 톤이므로 서비스 / 공장이 주입되는 모든 장소에서 동일한 인스턴스가 공유됩니다.

그렇다면 어느 것을 선호해야합니까? 어느 쪽이든-그들은 너무 유사하여 차이점이 사소합니다. 둘 중 하나를 선택하는 경우 구성 방법을 알고 있어야 제대로 구현할 수 있습니다.


서비스 함수는 "아무것도 반환하지 않습니다", 사용자가 자신의 return 문을 지정하지 않으면 생성 된 객체를 암시 적으로 반환합니다.
Cryptovirus

나는 수익을 말할 때, 나는 서비스 기능 구현의 관점에서 말은 ... 당신이 그것을 잘못 해석 있다고 생각
pixelbits

공장도 하나의 도시인지 확실합니까?
Martian2049

5

나는 그 차이를 알아 내기 위해 시간을 보냈다.

그리고 팩토리 함수는 모듈 패턴을 사용하고 서비스 함수는 표준 Java 스크립트 생성자 패턴을 사용한다고 생각합니다.


2

팩토리 패턴은 객체뿐만 아니라 함수와 값을 반환 할 수 있으므로 더 유연합니다.

서비스 패턴 IMHO에는 공장에서 쉽게 할 수있는 모든 작업이 포함되어 있기 때문에 많은 점이 없습니다. 예외는 다음과 같습니다.

  • 어떤 이유로 든 인스턴스화 된 서비스의 선언 된 유형에 관심이있는 경우-서비스 패턴을 사용하면 생성자가 새 서비스의 유형이됩니다.
  • 이미 다른 곳에서 사용하고있는 생성자 함수가 있다면 서비스로 사용하고 싶을 수도 있습니다 (물론 아무것도 주입하지 않으려는 경우에는 아마 많이 사용하지는 않습니다!).

서비스 패턴은 구문 관점에서 새 오브젝트를 작성 하는 약간 더 좋은 방법이지만 인스턴스화하는 데 더 많은 비용이 듭니다. 다른 사람들은 앵귤러가 "new"를 사용하여 서비스를 생성한다고 말했지만 이것은 사실이 아닙니다. 모든 서비스 생성자가 다른 수의 매개 변수를 가지고 있기 때문에 그렇게 할 수는 없습니다. 실제로 각도는 팩토리 패턴을 내부적으로 사용하여 생성자 함수를 래핑합니다. 그런 다음 자바 스크립트의 "새"연산자 를 시뮬레이션 하여 영리한 혼란스러운 포커를 수행 하여 가변 수의 주입 가능한 인수로 생성자를 호출합니다.하지만 팩토리 패턴을 직접 사용하는 경우이 단계를 생략 할 수 있으므로 암호.


공장은 상대적으로 값 비싼 클로저를 사용하고 서비스 (클래스)는 프로토 타입을 활용할 수 있으므로 팩토리보다 서비스를 구성하는 것이 더 효율적입니다.
jacob

@jacob 클로저에 대해 무슨 뜻인지 잘 모르시겠습니까? 팩토리는 객체를 반환하는 함수일뿐입니다. 리턴 된 오브젝트에 "개인"상태가 필요한 경우에만 클로저를 사용해야합니다. 생성자 (서비스)를 사용한 경우에도 여전히 동일한 작업을 수행해야합니다. 그래도 프로토 타입에 대해 설명 합니다. 원한다면 공장에서이 작업을 수행 할 있습니다.
Dan King

function MyFactory(dep1) { var $$foo = 'bar', factory = {}; Object.defineProperties(factory.prototype, { foo: { value: $$foo } }); return factory; } function MyService(dep1) { var $$foo = 'bar'; Object.defineProperties(MyService.prototype, { foo: { value: $$foo } }); } MyFactory와 MyService는 모두 프로토 타입을 사용하지만 MyFactory는 여전히 반환되는 객체를 구성해야하는 성능 저하를 가져옵니다. 두 예제 모두 개인 정보가 있지만 MyService에는 성능 차이가 없습니다.
jacob

1
나에게 차이점은 방법없이 공장을 직접 사용할지 여부입니다 MyFactory(someArgument)(ex $http()). 생성자를 참조하는 서비스에서는 불가능합니다 MyService(someArgument).
jacob

객체 생성 시간에, 나는 팩토리 = {}가 생성자를 호출 할 때 "this"를 초기화하는 것보다 더 많은 성능 히트를 어떻게 보지 못합니까? 그리고 팩토리에서 생성자를 감싸고 "신규"를 시뮬레이션하기 위해 후프를 뛰어 넘어야 의존성이 주입 될 때 각도 측면에서 더 큰 성능 히트가 발생한다고 생각합니다.
Dan King
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.