サービスと工場について混乱


618

私が理解しているように、ファクトリー内でコントローラーに注入されるオブジェクトを返します。サービス内では、this何も返さずにオブジェクトを使用して処理しています。

私は、サービスは常にシングルトンであり、すべてのコントローラーに新しいファクトリー・オブジェクトが注入されると想定していました。しかし、結局のところ、ファクトリオブジェクトもシングルトンですか?

デモするコードの例:

var factories = angular.module('app.factories', []);
var app = angular.module('app',  ['ngResource', 'app.factories']);

factories.factory('User', function () {
  return {
    first: 'John',
    last: 'Doe'
  };
});

app.controller('ACtrl', function($scope, User) {
  $scope.user = User;
});

app.controller('BCtrl', function($scope, User) {
  $scope.user = User;
});

変更user.firstするACtrlと、たとえばシングルトンも変更されることuser.firstがわかります。BCtrlUser

私の仮定は、新しいインスタンスがファクトリーを持つコントローラーにインジェクトされたということでしたか?


4
「module.service」と「module.factory」の横に、AngularJSでサービスを作成する方法が2つあります。詳細については、ブログ投稿を確認してください:「4つの方法で(シングルトン)AngularJSサービスを作成する方法
Emil van Galen

回答:


600

すべての角度のサービスはシングルトンです:

ドキュメント(「シングルトンとしてのサービス」を参照):https : //docs.angularjs.org/guide/services

最後に、すべてのAngularサービスはアプリケーションシングルトンであることを認識することが重要です。これは、インジェクタごとに特定のサービスのインスタンスが1つしかないことを意味します。

基本的に、サービスとファクトリーの違いは次のとおりです。

app.service('myService', function() {

  // service is just a constructor function
  // that will be called with 'new'

  this.sayHello = function(name) {
     return "Hi " + name + "!";
  };
});

app.factory('myFactory', function() {

  // factory returns an object
  // you can run some code before

  return {
    sayHello : function(name) {
      return "Hi " + name + "!";
    }
  }
});

$ provideに関するこのプレゼンテーションを確認してくださいhttp : //slides.wesalvaro.com/20121113/#/

これらのスライドは、AngularJのいずれかのミートアップで使用されました:http ://blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html


13
サービス、ファクトリ、提供の違いについて説明しているstackoverflow.com/questions/15666048/…も参照してください。
Mark Rajcok 2013年

31
公式ドキュメントは間接的に[シック!十分に明確ではない]は、ファクトリでサービスを定義しても、一度だけ作成されることを意味します。言い換えれば、参照(注入ポイント)と呼ばれるように、それが再び作成されることはありません。どちらの方法でも、インジェクターごとに1つのインスタンスが生成されます。
honzajde 2013年

3
「サービスは単に「new」で呼び出されるコンストラクター関数です」とあなたは言うが、それは誤解を招くと思う。私はそれが舞台裏で呼び出されるとは思わない、私は開発者がnewそれを呼び出す責任があると思います。
Tim Kindberg 2013

5
@ nfiniteloop、3574行目付近のソースコードを確認してください。ファクトリーはプロバイダーの$ getメソッドであり、サービスは提供された関数で$ injector.instantiateを呼び出し、次にnewを呼び出すメソッドを使用してファクトリーを生成します。(ドキュメントを参照
市民の

14
サービスは、それを参照することによって、あなたが使用したシングルトンのようなものであるという印象を受けました。そして、ファクトリーは毎回新しいオブジェクトを返すシングルトンでした。つまり、サービスは「車」を1つ提供し、プロジェクト内のすべてがこの車を使用します。工場は、工場を呼び出すたびに新しい車を提供します。1つはシングルトンを返すシングルトンで、もう1つはオブジェクトを返すシングルトンでした。誰か説明できますか?すべてをシングルトンと呼んでも、複数のものを参照できるため、役に立ちません。
user2483724 14年

380

私にとって啓示は、すべてが同じように動作することに気付いたときに起こりました。何かを1回実行し、取得した値を格納し、依存性注入を通じて参照されたときに、同じ格納された値を消去します。

私たちが持っているとしましょう:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

3つの違いは次のとおりです。

  1. aの保存された値は、runningから取得されます。fnつまり、fn()
  2. bの保存値はnewing から取得されます。fnつまり、new fn()
  3. cの格納された値は、最初にnewing によってインスタンスを取得し、fn次に$getインスタンスのメソッドを実行することから取得されます

つまり、angular内にキャッシュオブジェクトのようなものがあります。各インジェクションの値は、最初にインジェクションされたときに一度だけ割り当てられます。

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

これがthis、サービスで使用しthis.$get、プロバイダーでaを定義する理由です。

お役に立てれば。


54
最後に、正気な説明。Angularは正気ではなく、非常に悪いので痛いです。
osiris 2015

8
これは実際に工場、サービス、プロバイダーがシングルトン値を返す理由の質問に答えるため、受け入れられる答えになるはずです。他の答えは、工場、サービス、プロバイダーの違いを説明していますが、シングルトンの側面には触れません。
wmock

3
私はこれが好きです...他のブロガーから数千行の文章を読んだとき。しかし、私はこれを読んだ...私はすべてを理解している3.
tsohtan

@osiris同意する。嫌いです。緊密に結びついているので、歯がすごくします。
トーマス

2
プロバイダーを使用するときに$ getの実装を提供する必要がありますか?
Victor

95

実例

「hello world」の例

factory/ service/ provider

var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!"
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!"
        }
    };
});

//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {
    // In the provider function, you cannot inject any
    // service or factory. This can only be done at the
    // "$get" method.

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});


function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {

    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}​

57

次のように、コンストラクター関数を返す方法もあるので、ファクトリーで新しいクラスを返すことができます。

function MyObjectWithParam($rootScope, name) {
  this.$rootScope = $rootScope;
  this.name = name;
}
MyObjectWithParam.prototype.getText = function () {
  return this.name;
};

App.factory('MyObjectWithParam', function ($injector) {
  return function(name) { 
    return $injector.instantiate(MyObjectWithParam,{ name: name });
  };
}); 

したがって、MyObjectWithParamを使用するコントローラーでこれを行うことができます。

var obj = new MyObjectWithParam("hello"),

ここで完全な例を参照してください:http :
//plnkr.co/edit/GKnhIN?p=preview

そして、ここで議論されたグーグルグループページ:https : //groups.google.com/forum/#!msg / angular / 56sdORWEoqg /
b8hdPskxZXsJ


あなたの例を使った縮小化に問題があります。これに注釈を付ける方法を知っていますか?
PAL

2
はい、Angularの縮小表記が存在します。次のように App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); なります。詳細については、こちらをご覧ください: docs.angularjs.org/tutorial/step_05
JustGoscha

4
.service代わりに使用できるのに、なぜこれをしたいのですか?
フラップ、2015年

私は@flupと同じ考えを持っていました。@justgoscha、(いくつかのメリットがある?percieved使用しての).factoryとは反対には.service
xandercoded

5
サービスはシングルトンだからだと思います。ここで作成したのは、基本的には新しいクラスです。したがって、自動車サービスファクトリーのようなものを作成してnew Car('BMW')からnew Car('Ford')、それらを作成しても、同じ変数やすべてを共有することはできません。
JustGoscha

51

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

サービス

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

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

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

工場

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

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

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

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

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


6
これは私には理にかなっています。彼の工場は、新しいオブジェクトを作成するための青写真を返します。

27

最初の答えに加えて、.service()は、コードをよりオブジェクト指向のスタイル(C#/ Java)で記述した人向けです(このキーワードを使用し、プロトタイプ/コンストラクター関数を介してオブジェクトをインスタンス化します)。

Factoryは、javascript / functionスタイルのコーディングにより自然なコードを作成する開発者向けです。

angular.js内の.serviceおよび.factoryメソッドのソースコードを見てください。内部的にはすべてプロバイダーメソッドを呼び出しています。

  function provider(name, provider_) {
    if (isFunction(provider_)) {
      provider_ = providerInjector.instantiate(provider_);
    }
    if (!provider_.$get) {
      throw Error('Provider ' + name + ' must define $get factory method.');
    }
    return providerCache[name + providerSuffix] = provider_;
  }

  function factory(name, factoryFn) { \
    return provider(name, { $get: factoryFn }); 
  }

  function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

25

非常に簡単:

.service-登録された関数はコンストラクターとして呼び出されます(別名「新着」)

.factory-登録された関数は単純な関数として呼び出されます

どちらも一度呼び出されると、シングルトンオブジェクトがアプリの他のコンポーネントに挿入されます。


6
はい。物事を実際よりも複雑にしないようにしましょう
flup

20

すべてのプロバイダーは同じように機能します。別の方法はservicefactoryproviderちょうどあなたがより少ないコードで同じことを実現しましょう。

PS valueともありconstantます。

チェーンの最初providerと最後の特殊なケースにはそれぞれvalue、追加の制限があります。そのため、それらの間で決定するには、少ないコードで目的を達成できるかどうかを自問する必要があります。

ここに私が何を意味するかを示す写真があります:

ここに画像の説明を入力してください

内訳と参照ガイドは、この画像を取得したブログの投稿で確認できます。

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


サービスはシングルトンと言われていますが、注入するたびに新しいインスタンスが作成されると、どうしてシングルトンになりますか?
Ankur Marwaha 2016

1
@AnkurMarwaha新しいインスタンスは毎回作成されるのではなく、1回だけ作成され、AngularJSによってキャッシュされます。これは、プロバイダー、ファクトリー、サービスなどを使用しているかどうかに当てはまります。これを使用してconsole.log()、複数のコントローラーに注入して確認できます。
Luis Perez

Luis、あなたのコメントは言うように受け入れられた回答と矛盾します-最後に、すべてのAngularサービスはアプリケーションシングルトンであることを認識することが重要です。これは、インジェクターごとに特定のサービスのインスタンスが1つしかないことを意味します。
Ankur Marwaha 2016

@AnkurMarwaha多分私は何かを誤解しています。「すべてのAngularサービスがアプリケーションシングルトンであることを理解することが重要です」とおっしゃっていました。シングルトンであるということは、一度しか作成されないということです。これは、「新しいインスタンス毎回作成されるのではなく、一度だけ作成されてキャッシュされる...」と私が言ったことです。競合が発生している場所をより詳細に指摘できますか?
Luis Perez

1
ああ、混乱が見えます。「インジェクター」は角張ったオブジェクトです。「注射」を担当しています。例、コントローラーが最初に実行されるとき、「インジェクター」はパラメーターを調べ、それぞれを注入します。アプリ全体に対して「インジェクター」は1つしかありません。インジェクターは、特定のファクトリーまたはサービスを作成すると、インスタンスを保持して再利用します。つまり、シングルトンです。したがって、アプリごとに1つのインジェクターと、インジェクターごとに特定のサービスのインスタンスが1つしかありません。ほとんど角度のアプリケーションは、唯一などしたがって、1つのアプリ、1つのインジェクタ、任意のサービスのため、1つのインスタンスコントローラ、持っている
ルイス・ペレス

13

以下に、サービスとファクトリーの違いを確認するのに役立つ可能性のある、いくつかのサービスとファクトリーの例を示します。基本的に、サービスには「新しい...」が呼び出され、すでにインスタンス化されています。ファクトリは自動的にインスタンス化されません。

基本的な例

単一のメソッドを持つクラスオブジェクトを返す

以下は、単一のメソッドを持つサービスです。

angular.service('Hello', function () {
  this.sayHello = function () { /* ... */ };
});

次に、メソッドを使用してオブジェクトを返すファクトリを示します。

angular.factory('ClassFactory', function () {
  return {
    sayHello: function () { /* ... */ }
  };
});

値を返す

数値のリストを返すファクトリ:

angular.factory('NumberListFactory', function () {
  return [1, 2, 3, 4, 5];
});

console.log(NumberListFactory);

数値のリストを返すサービス:

angular.service('NumberLister', function () {
  this.numbers = [1, 2, 3, 4, 5];
});

console.log(NumberLister.numbers);

どちらの場合も出力は同じで、数値のリストです。

高度な例

ファクトリーを使用した「クラス」変数

この例では、CounterFactoryを定義します。カウンターをインクリメントまたはデクリメントし、現在のカウントを取得したり、作成されたCounterFactoryオブジェクトの数を取得したりできます。

angular.factory('CounterFactory', function () {
  var number_of_counter_factories = 0; // class variable

  return function () {
    var count = 0; // instance variable
    number_of_counter_factories += 1; // increment the class variable

    // this method accesses the class variable
    this.getNumberOfCounterFactories = function () {
      return number_of_counter_factories;
    };

    this.inc = function () {
      count += 1;
    };
    this.dec = function () {
      count -= 1;
    };
    this.getCount = function () {
      return count;
    };
  }

})

を使用CounterFactoryして複数のカウンターを作成します。クラス変数にアクセスして、作成されたカウンターの数を確認できます。

var people_counter;
var places_counter;

people_counter = new CounterFactory();
console.log('people', people_counter.getCount());
people_counter.inc();
console.log('people', people_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());

places_counter = new CounterFactory();
console.log('places', places_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());
console.log('counters', places_counter.getNumberOfCounterFactories());

このコードの出力は次のとおりです。

people 0
people 1
counters 1
places 0
counters 2
counters 2

それは便利な例です、number_of_counter_factoriesはCounterFactoryクラスのメタ属性のようなものですよね?この例はサービスで複製可能であることを理解しています(私が間違っていれば教えてください)、この場合の意味上の違いは何でしょうか?
geom 2015

便利な例!つまり、これは基本的に、ファクトリでは、サービスに入らない追加の抽象化レイヤーを持つことができることを意味します。ただし、何が返されても、「new」が使用されると、その新しいインスタンスが返されます。returnブロック内で宣言されていない変数はすべてシングルトンになります。私はそれを正しく理解しましたか?
スワニディ

@Swanidhi基本的にはい、ファクトリでシングルトンである変数を宣言できます。それが私がそれらを「クラス」変数と呼んだ理由です。

13

「ファクトリ」と「サービス」は、角度でDI(依存性注入)を実行する異なる方法です。

したがって、以下のコードに示すように、「サービス」を使用してDIを定義すると、これにより、「Logger」オブジェクトの新しいGLOBALインスタンスが作成され、関数に注入されます。

app.service("Logger", Logger); // Injects a global object

「ファクトリ」を使用してDIを定義すると、インスタンスは作成されません。メソッドを渡すだけで、後でコンシューマは内部でオブジェクトインスタンスのファクトリを呼び出す必要があります。

app.factory("Customerfactory", CreateCustomer);

以下は、「サービス」のDIプロセスが「ファクトリ」とどのように異なるかを視覚的に示す簡単な画像です。

ここに画像の説明を入力してください

シナリオに応じてさまざまなタイプのオブジェクトを作成する場合は、ファクトリを使用する必要があります。たとえば、シナリオに応じて、単純な「Customer」オブジェクト、「Address」オブジェクトを含む「Customer」、または「Phone」オブジェクトを含む「Customer」を作成します。この段落の詳細な説明は次のとおりです

ユーティリティ、ロガー、エラーハンドラーなどのユーティリティまたは共有関数を挿入する場合は、サービスを使用する必要があります。


この質問や他の同様の質問で私が見たすべての回答は、機構と構文の違いを特定しています。この答えは、あなたがどちらか一方を選択する本当の理由を与えます。それはセマンティクスの問題であり、名前、サービス、またはファクトリーを見ると、それらの目的とそれらの使用方法が伝達されます。
Joe Mayo

8

サービススタイル:(おそらく最も単純なもの)は実際の関数を返します:注入された関数参照に()を追加するだけで呼び出すことができるユーティリティ関数を共有するのに役立ちます。

AngularJSのサービスは、一連の関数を含むシングルトンJavaScriptオブジェクトです

var myModule = angular.module("myModule", []);

myModule.value  ("myValue"  , "12345");

function MyService(myValue) {
    this.doIt = function() {
        console.log("done: " + myValue;
    }
}

myModule.service("myService", MyService);
myModule.controller("MyController", function($scope, myService) {

    myService.doIt();

});

ファクトリスタイル:(より複雑ですがより洗練されています)関数の戻り値を返します:Javaのnew Object()のようなオブジェクトをインスタンス化します。

ファクトリーは値を作成する関数です。サービス、コントローラーなどがファクトリーから注入された値を必要とする場合、ファクトリーはオンデマンドで値を作成します。作成された値は、注入が必要なすべてのサービス、コントローラーなどで再利用されます。

var myModule = angular.module("myModule", []);

myModule.value("numberValue", 999);

myModule.factory("myFactory", function(numberValue) {
    return "a value: " + numberValue;
})  
myModule.controller("MyController", function($scope, myFactory) {

    console.log(myFactory);

});

プロバイダースタイル:(完全な、構成可能なバージョン)は、関数の$ get関数の出力を返します:構成可能。

AngularJSのプロバイダーは、作成できるファクトリーの最も柔軟な形式です。プロバイダーをモジュールに登録するには、代わりにprovider()関数を使用します。

var myModule = angular.module("myModule", []);

myModule.provider("mySecondService", function() {
    var provider = {};
    var config   = { configParam : "default" };

    provider.doConfig = function(configParam) {
        config.configParam = configParam;
    }

    provider.$get = function() {
        var service = {};

        service.doService = function() {
            console.log("mySecondService: " + config.configParam);
        }

        return service;
    }

    return provider;
});

myModule.config( function( mySecondServiceProvider ) {
    mySecondServiceProvider.doConfig("new config param");
});

myModule.controller("MyController", function($scope, mySecondService) {

    $scope.whenButtonClicked = function() {
        mySecondService.doIt();
    }

});

src jenkov

<!DOCTYPE html>
    <html ng-app="app">
    <head>
    	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
    	<meta charset=utf-8 />
    	<title>JS Bin</title>
    </head>
    <body ng-controller="MyCtrl">
    	{{serviceOutput}}
    	<br/><br/>
    	{{factoryOutput}}
    	<br/><br/>
    	{{providerOutput}}
    
    	<script>
    
    		var app = angular.module( 'app', [] );
    
    		var MyFunc = function() {
    
    			this.name = "default name";
    
    			this.$get = function() {
    				this.name = "new name"
    				return "Hello from MyFunc.$get(). this.name = " + this.name;
    			};
    
    			return "Hello from MyFunc(). this.name = " + this.name;
    		};
    
    		// returns the actual function
    		app.service( 'myService', MyFunc );
    
    		// returns the function's return value
    		app.factory( 'myFactory', MyFunc );
    
    		// returns the output of the function's $get function
    		app.provider( 'myProv', MyFunc );
    
    		function MyCtrl( $scope, myService, myFactory, myProv ) {
    
    			$scope.serviceOutput = "myService = " + myService;
    			$scope.factoryOutput = "myFactory = " + myFactory;
    			$scope.providerOutput = "myProvider = " + myProv;
    
    		}
    
    	</script>
    
    </body>
    </html>

jsbin

<!DOCTYPE html>
<html ng-app="myApp">
<head>
	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
	<meta charset=utf-8 />
	<title>JS Bin</title>
</head>
<body>
<div ng-controller="MyCtrl">
    {{hellos}}
</div>
	<script>

	var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!"
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!"
        }
    };
});
    
//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});
        

function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
    
    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}
	</script>

</body>
</html>

jsfiddle


2

基本的な違いは、プロバイダーはプリミティブ(非オブジェクト)、配列、またはコールバック関数の値をファクトリー宣言済み変数に設定できるため、オブジェクトを返す場合は明示的に宣言して返す必要があることです。

一方、サービスは、サービス宣言変数をオブジェクトに設定するためにのみ使用できるため、オブジェクトの明示的な作成と返却を回避できる一方で、thisキーワードを使用できます。

または、簡単に言うと、「サービスはオブジェクトのみに限定されるのに対し、プロバイダーはより一般的な形式です」。


2

これが、デザインパターンの観点での違いを理解した方法です。

サービス:タイプを返します。タイプが変更されて、そのタイプのオブジェクトが作成されます。Javaの例えが使用される場合、ServiceはJavaクラス定義を返します。

Factory:すぐに使用できる具象オブジェクトを返します。Javaアナロジーでは、ファクトリーはJavaオブジェクトを返します。

(私も含めて)人を混乱させることが多いのは、サービスまたはファクトリをコードに挿入すると同じように使用できるため、どちらの場合でもコードで取得できるのは、すぐに呼び出すことができる具体的なオブジェクトであるということです。つまり、サービスの場合、angularはあなたに代わってサービス宣言で「新規」を呼び出します。これは複雑な概念だと思います。


1

これは、Service Vs Factory Vs Providerを理解するための最良かつ短い答えになります

出典https : //groups.google.com/forum/#!msg / angular / 56sdORWEoqg / HuZsOsMvKv4J

ここで、ベンデモで 言っていることhttp://jsbin.com/ohamub/1/edit?html,output

「コードには主な違いを示すコメントが含まれていますが、ここで少し詳しく説明します。注意点として、頭を使っているだけなので、何か間違ったことを言ったらお知らせください。

サービス

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

結果:serviceNameを注入可能な引数として宣言すると、module.serviceに渡される実際の関数参照が提供されます。

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

工場

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

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

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

プロバイダー

構文:module.provider( 'providerName'、function);

結果:providerNameを注入可能な引数として宣言すると、module.providerに渡された関数参照の$ getメソッドを呼び出すことによって返される値が提供されます。

使用法:インスタンスを作成するために新規作成できる「クラス」関数を返す場合に役立ちますが、注入する前になんらかの構成が必要です。プロジェクト間で再利用可能なクラスにおそらく役立つでしょうか?これについてはまだ漠然としている」ベン


1

私はしばらくの間この混乱を抱えていましたが、ここで簡単な説明を提供できるように最善を尽くしています。これが役立つことを願っています!

angular .factoryそして、angular .serviceの両方が同じようにサービスや仕事を初期化するために使用されています。

唯一の違いは、サービスを初期化する方法です。

どちらもシングルトンです


var app = angular.module('app', []);


工場

app.factory(<service name><function with a return value>

戻り値を持つ関数からサービスを初期化する場合は、このfactoryメソッドを使用する必要があります。

例えば

function myService() {
  //return what you want
  var service = {
    myfunc: function (param) { /* do stuff */ }
  }
  return service;
}

app.factory('myService', myService);

このサービスを注入するとき(たとえば、コントローラーに):

  • Angularは与えられた関数を(として)呼び出しmyService()オブジェクトを返します
  • シングルトン-1回だけ呼び出され、保存され、同じオブジェクトを渡します。


サービス

app.service(<service name><constructor function>

(キーワードを使用して)コンストラクター関数からサービスを初期化するthis場合は、このserviceメソッドを使用する必要があります。

例えば

function myService() {
  this.myfunc: function (param) { /* do stuff */ }
}

app.service('myService', myService);

このサービスを注入するとき(たとえば、コントローラーに):

  • Angularはnew与えられた関数(としてnew myService())を使ってオブジェクトを返します
  • シングルトン-1回だけ呼び出され、保存され、同じオブジェクトを渡します。


注:あなたが使用している場合factory<constructor function>service<function with a return value>、それが動作しません。


例-デモ


1

これは、Pascal Prechtのブログ投稿のおかげで、違いを理解するのに役立ちました。

サービスは、名前とサービスを定義する関数を使用するモジュールのメソッドです。その特定のサービスを注入して、コントローラー、ディレクティブ、フィルターなどの他のコンポーネントで使用できます。ファクトリーはモジュールのメソッドであり、ファクトリーを定義する名前と関数も受け取ります。また、サービスで行ったのと同じように注入して使用することもできます。

newで作成されたオブジェクトは、コンストラクター関数のprototypeプロパティの値をプロトタイプとして使用するため、Object.create()を呼び出すAngularコードを見つけました。これは、インスタンス化されたときにサービスコンストラクター関数であると考えています。ただし、ファクトリ関数は実際には呼び出される関数にすぎないため、ファクトリのオブジェクトリテラルを返す必要があります。

これは私が工場で見つけた角度1.5コードです:

var needsRecurse = false;
    var destination = copyType(source);

    if (destination === undefined) {
      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
      needsRecurse = true;
    }

factory()関数のAngularソースコードスニペット:

 function factory(name, factoryFn, enforce) {
    return provider(name, {
      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
    });
  }

これは、渡された名前とファクトリー関数を受け取り、ファクトリー関数である$ getメソッドを持つ同じ名前のプロバイダーを返します。インジェクターに特定の依存関係を要求するときはいつでも、基本的に$ get()メソッドを呼び出すことにより、対応するプロバイダーにそのサービスのインスタンスを要求します。そのため、プロバイダーを作成するときに$ get()が必要です。

以下は、サービス用の角度1.5コードです。

function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

service()を呼び出すと、実際にはfactory()が呼び出されることがわかります。ただし、サービスコンストラクター関数をそのままファクトリーに渡すだけではありません。また、指定されたコンストラクターによってオブジェクトをインスタンス化するようインジェクターに要求する関数も渡します。

言い換えると、MyServiceをどこかに挿入すると、コード内で次のことが起こります。

MyServiceProvider.$get(); // return the instance of the service

再度述べると、サービスはファクトリを呼び出します。ファクトリは、対応するプロバイダーの$ get()メソッドです。さらに、$ injector.instantiate()は、コンストラクター関数を使用して最終的にObject.create()を呼び出すメソッドです。これが、サービスで「this」を使用する理由です。

ES5の場合、service()またはfactory()のどちらを使用するかは関係ありません。サービスのプロバイダーを作成するために呼び出されるのは常にファクトリです。

サービスでもまったく同じことができます。サービスはコンストラクタ関数ですが、オブジェクトリテラルを返すことを妨げるものではありません。そのため、サービスコードを取得して、基本的にはファクトリとまったく同じように記述できます。つまり、オブジェクトを返すファクトリとしてサービスを記述できます。

ほとんどの人がサービスよりも工場の使用を勧めるのはなぜですか?これは、Pawel Kozlowskiの本「AngularJSを使用したWebアプリケーション開発の習得」から得られた、私が見た中で最高の答えです。

ファクトリーメソッドは、オブジェクトをAngularJS依存性注入システムに取り込む最も一般的な方法です。非常に柔軟で、高度な作成ロジックを含めることができます。ファクトリは通常の関数であるため、「プライベート」変数をシミュレートするために新しい字句スコープを利用することもできます。特定のサービスの実装の詳細を隠すことができるので、これは非常に便利です。」


1
  • では工場あなたは、実際に作成したオブジェクトの内部に工場をし、それを返します。
  • サービスあなただけの持っている標準機能使用 this関数を定義するキーワードを。
  • では、プロバイダがあります$getあなたが定義し、それを使用することができます取得するためにデータを返すオブジェクトが。

1

(:AngularJSでビジネスロジックを処理する3つの方法があり、もちろんYaakovののコーセラAngularJSに触発されています):

  1. サービス
  2. 工場
  3. プロバイダー

ここでは、ServiceFactoryについてのみ説明します

SERVICE

構文:

app.js

 var app = angular.module('ServiceExample',[]);
 var serviceExampleController =
              app.controller('ServiceExampleController', ServiceExampleController);
 var serviceExample = app.service('NameOfTheService', NameOfTheService);

 ServiceExampleController.$inject = ['NameOfTheService'] //very important as this 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;
     }     
}

index.html

<div ng-controller = "ServiceExampleController as serviceExample">
   {{serviceExample.data}}
</div>

サービスの主な機能:

  1. 遅延インスタンス化:サービスが注入されない場合、インスタンス化されません。したがって、それを使用するには、モジュールに注入する必要があります。

  2. シングルトン:複数のモジュールに注入された場合、すべてが特定の1つのインスタンスにのみアクセスできます。そのため、異なるコントローラ間でデータを共有すると非常に便利です。

工場

では、AngularJSのファクトリーについて話しましょう

最初に構文を見てみましょう:

app.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;
}

コントローラで上記の2つを使用します。

 var factoryOne = NameOfTheFactoryOne() //since it returns a function
 factoryOne.someMethod();

 var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
 factoryTwo.someMethod();

工場の特徴:

  1. このタイプのサービスは、工場の設計パターンに従います。ファクトリは、新しいオブジェクトまたはメソッドを作成する中心的な場所と考えることができます。

  2. これにより、シングルトンだけでなく、カスタマイズ可能なサービスも生成されます。

  3. この.service()メソッドは、常に同じタイプのサービス(シングルトン)を生成するファクトリです。その動作を設定する簡単な方法はありません。その.service()方法は通常、設定をまったく必要としないもののショートカットとして使用されます。



0

このアナロジーで違いを理解できます-いくつかの値を返す通常の関数と、新しいキーワードを使用してインスタンス化されるコンストラクター関数の違いを考えてください。したがって、ファクトリの作成は、いくつかの値を返す通常の関数の作成(プリミティブまたは一方、サービスの作成は、新しいキーワードを使用してインスタンスを作成できるコンストラクター関数(OOクラス)を作成するようなものです。唯一気付くのは、Serviceメソッドを使用してサービスを作成すると、AngularJSでサポートされている依存性注入メカニズムを使用して、そのインスタンスが自動的に作成されることです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.