Pascal Prechtによるブログ投稿のおかげで、これが違いを理解するのに役立ちました。
サービスは、サービスを定義する名前と関数を受け取るモジュール上のメソッドです。その特定のサービスを、コントローラー、ディレクティブ、フィルターなどの他のコンポーネントに挿入して使用できます。ファクトリはモジュールのメソッドであり、ファクトリを定義する名前と関数も取ります。また、サービスで行ったのと同じ方法で注入して使用することもできます。
newで作成されたオブジェクトは、コンストラクター関数のプロトタイププロパティの値をプロトタイプとして使用するため、Object.create()を呼び出すAngularコードを見つけました。これは、インスタンス化されたときのサービスコンストラクター関数であると思います。ただし、ファクトリ関数は実際には呼び出される関数にすぎないため、ファクトリのオブジェクトリテラルを返す必要があります。
これが私が工場で見つけたAngular1.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()を呼び出すメソッドです。そのため、サービスでは「これ」を使用しています。
ES5の場合、service()とfactory()のどちらを使用するかは関係ありません。サービスのプロバイダーを作成するのは、常に呼び出されるファクトリです。
ただし、サービスでもまったく同じことができます。サービスはコンストラクター関数ですが、オブジェクトリテラルを返すことを妨げるものではありません。したがって、サービスコードを取得して、基本的にファクトリとまったく同じように記述できます。つまり、オブジェクトを返すファクトリとしてサービスを記述できます。
ほとんどの人がサービスよりも工場の使用を推奨するのはなぜですか?これは、Pawel Kozlowskiの著書「AngularJSを使用したWebアプリケーション開発の習得」から得られた、私が見た中で最高の答えです。
ファクトリメソッドは、オブジェクトをAngularJS依存性注入システムに取り込む最も一般的な方法です。非常に柔軟性があり、高度な作成ロジックを含めることができます。ファクトリは通常の関数であるため、新しい字句スコープを利用して「プライベート」変数をシミュレートすることもできます。特定のサービスの実装の詳細を非表示にできるため、これは非常に便利です。」