angular.service対angular.factory


1065

angular.factory()angular.service()の両方がサービスの宣言に使用されるのを見てきました。ただし、公式ドキュメントに angular.serviceどこにもありません

2つの方法の違いは何ですか?
何が何のために使われるべきですか?



4
「[angularjs]サービスファクトリー」を検索しましたが、既にそれについての質問があることも思い出しました(ある時点で自分でこの質問を書こうと思ったためです)。
Mark Rajcok、2013年

2
検索で、角括弧はタグを意味しますか?
ジェイコブ2013年

11
@Jacob角括弧で検索を絞り込んでいます。[angularjs]ディレクティブ-angularjsでタグ付けされた質問の「ディレクティブ」を検索します
Mahbub 2013年

1
@Mahbub言い換えれば、「はい」:)
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を使うよりも。)


もう1つ、それらはすべてシングルトンです...

また、どちらの場合でも、angularはシングルトンの管理に役立ちます。サービスまたは関数を挿入する場所や回数に関係なく、同じオブジェクトまたは関数への同じ参照を取得します。(ファクトリーが数値や文字列のような値を返す場合を除いて。その場合、常に同じ値を取得しますが、参照は取得しません。)


2
Newableよりもオブジェクトコンストラクタと呼ぶ方が良いでしょうか?
markyzm 2014年

2
@Hugo、私はあなたが両方で同じことを効果的に達成できることを示していました、それは構文が異なるというだけです。
Gil Birman、2014

105
サービスと工場の両方が必要であると確信するまでに、サービスと工場の違いについて何回読まなければならないかわからない
DMac the Destroyer

10
「to new」という動詞はすでにありますが、これは「インスタンス化」です。参考までに。:)
sscarduzio 2015年

7
ファクトリーは呼び出される関数なので、何でも返すことができます。一方、サービスはを介してAngularによってインスタンス化されるnew fn()ため、インスタンスを返す必要があります。
Gil Birman、2015

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 2014

3
ただし、オブジェクトを返す場合は、これの代わりにそれを使用します。jsfiddle.net/Ne5P8/1221
MrB

@MrB、これは通常のJavaScript機能であり、Angularやこの質問のコンテキストに固有ではありません。
Om Shankar

@Om Shankar、上の答えは、違いはこのオブジェクトと返されたオブジェクトの使い方であることを示しています。「THIS」がサービスで使用されるデフォルト値であることを示していましたが、値を返すと、ファクトリとほぼ同じように動作します。ただし、反対に、ファクトリーは戻り値を必要とするように見えます。そうでない場合、エラーが発生します(この例ではjsfiddle.net/hmoc0q3v/1です)。
MrB、2014

247

主な違いは次のとおりです。

サービス

構文: module.service( 'serviceName', function );

結果:serviceNameを注入可能な引数として宣言すると、に渡される関数インスタンスが提供されますmodule.service

使用法:注入された関数参照に追加するだけで呼び出すことができるユーティリティ関数共有するのに役立ち( )ます。injectedArg.call( this )または同様に実行することもできます。

工場

構文: module.factory( 'factoryName', function );

結果:factoryNameを注入可能な引数として宣言すると、に渡される関数参照を呼び出すことによって返される値が提供されmodule.factoryます。

使用法:インスタンスを作成するために新規作成できる「クラス」関数を返すのに役立ちます。

以下は、サービスとファクトリーの使用例です。AngularJS ServiceとFactoryの詳細を読んでください。

AngularJSのドキュメント、サービスとファクトリーについて混乱しているstackoverflowに関する同様の質問を確認することもできます。


27
工場の使用例には同意しません。サービスとファクトリーの両方(関数が返されると仮定します。値またはオブジェクトである可能性があります)を新規作成できます。実際、サービスは、関数インスタンスが提供されるため、新規であることが保証されている唯一のオプションです。サービスよりもファクトリを使用する利点は、プロパティへのアクセスをある程度制御できることです-サービスのすべてのプロパティは本質的に公開されていますが、プライベートおよびパブリック自体。そして、私はプロバイダーを工場の工場と考えています-構成時に注入可能で構成可能なものだけです。
Drew R

1
@DrewRコメントをありがとう、ファクトリを使用したパブリックメソッドとプライベートメソッドの良い例を見つけました:stackoverflow.com/a/14904891/65025
edzillion

これについては、@ DrewRに同意する必要があります。以前はオブジェクトを返すためにファクトリーを使用しましたが、正直なところ、この時点では$providers常に使用するだけの価値があるかもしれません。
jedd.ahyoung 14年

サービスは自動的にコンストラクタをインスタンス化しますよね?
Martian2049

1
@DrewR-私の理解から、ファクトリーでできるのと同じように、サービスから同じ新しい効果を達成できるのは事実ですが、それが意図していることではありません。主な目標は、ユーティリティオブジェクトを返すだけで、より適切な構文を提供することです。これは、this.myFunc = function(){}サービスに書き込むだけです(コードを記述して、ファクトリで行う必要があるようなオブジェクトを作成する必要がなくなります)。 )。
BornToCode 2017年

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」にアタッチしたすべてのプロパティを使用できるようになります。

次に、いくつかの「プライベート」変数をコールバック関数に追加しましょう。これらはコントローラーから直接アクセスできませんが、必要に応じてこれらの「プライベート」変数を変更できるように、最終的に「サービス」にいくつかのゲッター/セッターメソッドを設定します。

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

ここで、これらの変数/関数を「サービス」にアタッチしていないことに気づくでしょう。後で使用または変更するために、単に作成しています。

  • baseUrlは、iTunes APIが必要とするベースURLです
  • _artistは、検索するアーティストです
  • _finalUrlは、iTunesを呼び出す最終的な完全に構築されたURLですmakeUrlは、iTunesと相性の良いURLを作成して返す関数です。

ヘルパー/プライベート変数と関数が用意できたので、「サービス」オブジェクトにいくつかのプロパティを追加しましょう。「サービス」をどのように設定しても、「myFactory」を渡すどのコントローラーでも直接使用できます。

アーティストを返すか設定するだけのsetArtistメソッドとgetArtistメソッドを作成します。また、作成したURLでiTunes APIを呼び出すメソッドを作成します。このメソッドは、iTunes APIからデータが返されると満たされるpromiseを返します。Angularでプロミスを使用した経験があまりない場合は、プロミスについて深く学ぶことを強くお勧めします。

以下のsetArtistはアーティストを受け入れ、アーティストを設定できます。getArtistは、アーティストのcallItunesを返します。最初に、$ httpリクエストで使用するURLを作成するために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がpromiseを返すため、.then()メソッドを使用して、iTunesデータでpromiseが満たされた場合にのみ$ scope.data.artistDataを設定できます。コントローラーが非常に「薄い」ことに気づくでしょう。ロジックと永続データはすべて、コントローラーではなくサービスにあります。

2)サービス
おそらく、サービスの作成を処理する際に知っておくべき最大のことは、「新しい」キーワードでインスタンス化されるということです。JavaScriptの達人にとって、これはコードの性質に大きなヒントを与えるはずです。JavaScriptのバックグラウンドが限られている方や、「新しい」キーワードの実際の動作に慣れていない方のために、最終的にサービスの性質を理解するのに役立つ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コンストラクターがオブジェクトを返していることがわかります。コードでそれを確認できるかどうかは関係ありません。次に、sayName関数は直接Personインスタンスではなくプロトタイプにあるため、Person関数が返すオブジェクトは、ルックアップが失敗したときにそのプロトタイプに委任されている必要があります。より簡単に言えば、tyler.sayName()を呼び出すと、インタープリターは「OK、先ほど作成した 'tyler'オブジェクトを見て、sayName関数を見つけて呼び出します。ちょっと待ってください、ここには表示されません。表示されるのは名前と年齢だけです。プロトタイプを確認させてください。うん、それはプロトタイプにあるように見えます。私はそれを呼ばせてください。」

以下は、「new」キーワードが実際にJavaScriptで何をしているのかを考える方法のコードです。基本的には、上記の段落のコード例です。「インタープリタービュー」、つまりインタープリターがコードをノート内に表示する方法を示しました。

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でサービスを作成することは理解しやすくなるはずです。

サービスを作成するときに理解する最大のことは、サービスが「新しい」キーワードでインスタンス化されることを知ることです。この知識と上記の例を組み合わせると、プロパティとメソッドを「this」に直接アタッチし、サービス自体から返されることを認識できるはずです。これを実際に見てみましょう。

最初にFactoryの例で行ったのとは異なり、オブジェクトを作成してからそのオブジェクトを返す必要はありません。これまでに何度も言及したように、「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;
  }

});

これで、ファクトリと同様に、setServiceist、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少し読みやすいことがわかりました。
タイラーコリアー2014年

3
ここであなたのブログを繰り返すことは間違っていませんが、それはグレタのブログ投稿であることに同意します。
Rクラベン2014年

5
フードの下でそれぞれが何をするかについての詳細な説明。ただし、なぜファクトリーではなくサービスを使用する理由と時期を明確にしていない。言い換えると、いつファクトリーから返されたオブジェクトよりも、新しいオブジェクトを使用したいのでしょうか。これが最大の混乱だと思います。
demisx 2014

2
基本的に、リモートサービスへの永続的な接続を作成する場合(例:常時接続(接続状態、通話履歴、データストレージ)を使用した例で述べたiTunes APIなど)は、Factoryを使用できます。サービスとして実装すると、APIから何かが必要になるたびに接続が再作成され、実際には何も格納できなくなります。サービスを再作成するたびに、空のデフォルトオブジェクトが取得されるためです。
Meki 2014年

4
@Aznim、それは正しいとは思いません。他の人が言ったように、どちらもシングルトンを提供します。
クリプトウイルス、2015年

35

手がかりは名前にあります

サービスと工場は互いに似ています。どちらも、他のオブジェクトに注入できるシングルトンオブジェクトを生成するため、しばしば同じ意味で使用されます。

これらは、異なるデザインパターンを実装するために意味的に使用されることを目的としています。

サービスはサービスパターンを実装するためのものです

サービスパターンとは、アプリケーションが論理的に一貫した機能単位に分割されるパターンです。例としては、APIアクセサーやビジネスロジックのセットなどがあります。

Angularは通常、サーバーからプルされた単なるJSONオブジェクトであるため、Angularでこれは特に重要であり、ビジネスロジックを配置する場所が必要です。

以下はGithubサービスの例です。Githubと通信する方法を知っています。それは、URLとメソッドについて知っています。これをコントローラーに注入すると、promiseが生成されて返されます。

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

工場もシングルトンを返すことに注意してください。

工場はコンストラクタを返すことができます

ファクトリはオブジェクトを返すだけなので、上記のように、コンストラクター関数を含め、任意のタイプのオブジェクトを返すことができます。

工場はオブジェクトを返します。サービスは新しい

もう1つの技術的な違いは、サービスと工場の構成方法にあります。オブジェクトを生成するサービス関数が新しくなります。ファクトリ関数が呼び出され、オブジェクトを返します。

  • サービスは新しいコンストラクタです。
  • ファクトリは単に呼び出され、オブジェクトを返します。

つまり、サービスでは、「this」に追加します。これは、コンストラクターのコンテキストでは、作成中のオブジェクトを指します。

これを説明するために、サービスとファクトリを使用して作成された同じ単純なオブジェクトを次に示します。

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

2
素晴らしい説明、ありがとう!また、インジェクタパラメータが必要な型がFactorysサンプルコードにありAuthorますPerson
mikhail-t

@ mik-Tに感謝します。タイプミスを修正しました。
超光速の2015

1
サービスパターンの使用が正しくありません-これはファクトリでなければなりません。.service()の代わりに.factory()を呼び出すと、まったく同じように機能することがわかります。サービスパターンは、コンストラクター関数で提供されることを意図しており、新しいオブジェクトを返す関数ではありません。Angularは、コンストラクター関数で(事実上) "new"を呼び出します。サービスが機能する唯一の理由は、オブジェクトを返すコンストラクター関数で「new」を呼び出すと、実際には作成されたオブジェクトではなく、返されたオブジェクトが返されるためです。また、工場はモデルだけでなく、好きなものを作成するために使用できます。
ダンキング

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)と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ステートメントを指定しない場合は、構築されたオブジェクトを暗黙的に返します(後者の場合、返されたオブジェクトは、ファクトリーのように作成およびキャッシュされるオブジェクトです)。
クリプトウイルス

私はあなたがそれを誤解していると思います... returnと言うとき、私はサービス関数の実装の観点から意味します
pixelbits

工場も単一の町であることを確認しますか?
Martian2049 2016年

5

私はその違いを理解するために少し時間を費やしました。

そして、ファクトリ関数はモジュールパターンを使用し、サービス関数は標準のjavaスクリプトコンストラクタパターンを使用すると思います。


2

ファクトリパターンは、関数や値、オブジェクトを返すことができるため、より柔軟です。

サービスパターンIMHOには、工場で同じように簡単に実行できるすべての機能があるため、あまり意味がありません。例外は次のとおりです。

  • なんらかの理由でインスタンス化されたサービスの宣言されたタイプを気にする場合-サービスパターンを使用する場合、コンストラクターは新しいサービスのタイプになります。
  • サービスとしても使用したい他の場所で使用しているコンストラクター関数が既にある場合(ただし、何かを挿入する場合はあまり使用しませんが!)

間違いなく、サービスパターンは構文の観点から新しいオブジェクトを作成するための少し優れた方法ですが、インスタンス化のコストも高くなります。他の人は、angularが「新規」を使用してサービスを作成することを示していますが、これは完全に真実ではありません。すべてのサービスコンストラクターが異なる数のパラメーターを持っているため、これを行うことはできません。angularが実際に行うことは、コンストラクター関数をラップするためにファクトリーパターンを内部で使用することです。次に、JavaScriptの「新しい」演算子をシミュレートする巧妙なジグザリーポケリーを実行し、可変数の注入可能な引数でコンストラクターを呼び出します。ただし、ファクトリパターンを直接使用するだけの場合は、この手順を省略できるため、ごくわずかに効率が向上します。コード。


工場は比較的高価なクロージャーを使用し、サービス(クラス)はプロトタイプを利用できるため、サービスは工場よりも効率的に構築できます。
ジェイコブ2015

@jacob閉鎖についてどういう意味かわかりませんか?ファクトリは、オブジェクトを返す関数にすぎません。返されたオブジェクトが「プライベート」状態を必要とする場合のみ、クロージャーを使用する必要があります。コンストラクタ(サービス)を使用した場合でも、同じことを行う必要があります。ただし、プロトタイプについては要点を述べます、必要であれば工場でこれを行うことできます。
ダンキング

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)
ジェイコブ2015

オブジェクトの構築時に、javascriptがコンストラクタを呼び出すときに「this」を初期化する以上に、factory = {}がパフォーマンスにどのように影響するかはわかりません。そして、コンストラクターをファクトリーでラップし、依存関係を注入できるように「新規」をシミュレートするためにフープをジャンプしなければならない場合、より大きなパフォーマンスヒットは角度のある側にあると思います。
ダンキング
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.