サービスは、タイプに関係なく、常にシングルトーン(単発)であることに注意してください。
注:シングルトンは、1つのインスタンスのみを持つことができるようにクラスを制限する設計パターンです。 このインスタンスを使用して、作業がどこで使用されても実行されます。
サービスの種類に移りましょう
定数
app.constant('fooConfig', { config1: true, config2: "Default config2" });
この定数は、ディレクティブのデフォルト設定によく使用されます。 そのため、ディレクティブを作成し、設定に加えていくつかの標準パラメーターを渡すことができるようにしたい場合、定数はこれを行う良い方法です。
定数の値は決定時に指定され、他の方法で変更することはできません。 定数値には、プリミティブまたはオブジェクトを指定できます。 また、定数はモジュールの設定段階で設定できます。 値は、実行段階およびそれ以降でのみ使用できます(コメントからの注意)。
価値
app.value('fooConfig', { config1: true, config2: "Default config2 but it can changes" });
変数は定数に似ていますが、変更できます。 多くの場合、ディレクティブのセットアップに使用されます。 この変数は、工場の切り捨てられたバージョンに似ており、サービス自体で計算できない値のみが含まれています。
工場
app.factory('foo', function() { var thisIsPrivate = "Private"; function getPrivate() { return thisIsPrivate; } return { variable: "This is public", getPrivate: getPrivate }; }); // ... app.factory('bar', function(a) { return a * 2; });
工場は最も頻繁に使用されるサービスです。 また、理解するのが最も簡単です。
ファクトリは、あらゆるタイプのデータを返すことができるサービスです。 このデータを作成するためのルールは含まれていません。 何かを返すだけです。 オブジェクトを操作するときは、 オープンモジュールテンプレートを使用するのが好きですが、必要に応じて別のアプローチを使用できます。
前述のように、すべてのタイプは
foo.variable
、
foo.variable
を1か所で変更すると、他の場所でも変更されます。
サービス
app.service('foo', function() { var thisIsPrivate = "Private"; this.variable = "This is public"; this.getPrivate = function() { return thisIsPrivate; }; });
サービス(総称名と特定のタイプを混同しないでください)は、ファクトリーのように機能します。 違いは、サービスがコンストラクターを使用することです。そのため、初めて使用する場合、
new Foo();
を実行し
new Foo();
オブジェクトのインスタンスを作成します。 このサービスを使用すると、同じオブジェクトが他の場所に戻ってくることに注意してください。
実際、このサービスは次のコードと同等です。
app.factory('foo2', function() { return new Foobar(); }); function Foobar() { var thisIsPrivate = "Private"; this.variable = "This is public"; this.getPrivate = function() { return thisIsPrivate; }; }
Foobar
はクラスです 。工場でインスタンス化し、最初に使用してから返します。 サービスと同様に、
Foobar
クラスのインスタンスは1回だけ作成され、次にファクトリが同じインスタンスを再び返すときに作成されます。
すでにクラスがあり、サービスでそれを使用したい場合、これを行うことができます:
app.service('foo3', Foobar);
プロバイダー
プロバイダーは、特別な方法で構成されたファクトリーです。 実際、最新の例のファクトリーは次のようになります。
app.provider('foo', function() { return { $get: function() { var thisIsPrivate = "Private"; function getPrivate() { return thisIsPrivate; } return { variable: "This is public", getPrivate: getPrivate }; } }; });
プロバイダーは
$get
関数を期待しています。これは、アプリケーションの他の部分にデプロイするものです。 したがって、
foo
をコントローラーに注入すると、
$get
関数が実装されます
ファクトリがはるかに単純なときにこのフォームを使用するのはなぜですか? プロバイダーは構成機能で構成できるためです。 そのため、次のようなことができます。
app.provider('foo', function() { var thisIsPrivate = "Private"; return { setPrivate: function(newVal) { thisIsPrivate = newVal; }, $get: function() { function getPrivate() { return thisIsPrivate; } return { variable: "This is public", getPrivate: getPrivate }; } }; }); app.config(function(fooProvider) { fooProvider.setPrivate('New value from config'); });
ここでは、
$get
関数を超えて
thisIsPrivate
を
thisIsPrivate
してから、設定関数で
thisIsPrivate
を変更できるように
setPrivate
関数を作成しました。 なぜこれを行う必要があるのですか? 工場にセッターを追加する方が簡単ではありませんか? 別の目標があります。
特定のオブジェクトを実装したいのですが、ニーズに合わせてカスタマイズする方法が必要です。 たとえば、JSONPを使用するリソースのラッパーサービスの場合、
restangular
などのサードパーティサービスで使用されるURLを構成できるようにしたいと考えています。 プロバイダーにより、目的に合わせて事前に構成することができます。
構成関数では、nameではなく
nameProvider
として指定する必要があることに注意してください。 その他の場合はすべて
name
示されます。
これを見て、アプリケーションでいくつかのサービスを既に構成していることを思い出してください。たとえば、
$routeProvider
と
$locationProvider
、それぞれルーティングとhtml5mode
$locationProvider
構成します。
ボーナス1:デコレーター
そのため、サービス
foo
に
greet
関数が欠けていると判断した
greet
、追加する必要があります。 工場を変更する必要がありますか? いや! あなたはそれを飾ることができます:
app.config(function($provide) { $provide.decorator('foo', function($delegate) { $delegate.greet = function() { return "Hello, I am a new function of 'foo'"; }; return $delegate; }); });
$provide
は、Angularがすべての内部サービスを作成するために使用するものです。 必要に応じて手動で使用することも、モジュールで提供されている関数を使用することもできます(装飾には
$provide
を使用する必要があります)。
$provide
は、サービスを装飾
$provide
の
decorator
関数を備えています。 装飾されたサービスの名前を取得し、コールバックはサービスの元のインスタンスである
$delegate
取得します。
ここでは、サービスを飾るために、何でもできます。 この例では、元のサービスに
greet
関数を追加しました。 次に、新しい変更されたサービスを返しました。
これで、使用時に新しい
greet
機能が追加されます。
サービスを装飾する機能は、サードパーティの開発者からのサービスを使用する場合に便利です。これは、プロジェクトにコピーしたり、さらに変更したりすることなく装飾できます。
注:定数を修飾することはできません。
ボーナス2:新しいインスタンスを作成する
サービスはシングルトンですが、新しいインスタンスを作成するシングルトンファクトリを作成できます。 それを掘り下げる前に、シングルトンサービスを持つことは、変更したくない良いアプローチであることに留意してください。 ただし、新しいインスタンスを生成する必要があるまれなケースでは 、次のようにできます。
// function Person( json ) { angular.extend(this, json); } Person.prototype = { update: function() { // ( :P) this.name = "Dave"; this.country = "Canada"; } }; Person.getById = function( id ) { // -, Person id return new Person({ name: "Jesus", country: "Spain" }); }; // app.factory('personService', function() { return { getById: Person.getById }; });
ここで、オブジェクトを初期化するためのJSONデータを受け取る
Person
オブジェクトを作成します。 次に、プロトタイプ内の関数(
Person
インスタンスのプロトタイプ内の関数)と
Person
内の関数(クラスの類似関数)を作成しました。
したがって、渡した識別子に基づいて新しい
Person
オブジェクトを作成するクラス関数があり(これは実際のコードになります)、各インスタンスはそれ自体を更新できます。 次に、それを使用するサービスを作成するだけです。
personService.getById
を呼び出す
personService.getById
に、新しい
Person
オブジェクトを作成します。これにより、さまざまなコントローラーでこのサービスを使用でき、ファクトリーがシングルトンの場合でも、新しいオブジェクトが作成されます。
彼の例については、 ジョシュ・デイビッド・ミラーに敬意を表します。
ボーナス3:CoffeeScript
CoffeeScriptは、クラスを作成するより良い方法を提供するため、サービスと便利に組み合わせることができます。 CoffeeScriptを使用したボーナス例2を見てみましょう。
app.controller 'MainCtrl', ($scope, personService) -> $scope.aPerson = personService.getById(1) app.controller 'SecondCtrl', ($scope, personService) -> $scope.aPerson = personService.getById(2) $scope.updateIt = () -> $scope.aPerson.update() class Person constructor: (json) -> angular.extend @, json update: () -> @name = "Dave" @country = "Canada" @getById: (id) -> new Person name: "Jesus" country: "Spain" app.factory 'personService', () -> { getById: Person.getById }
私の謙虚な意見では、今彼はよりきれいに見えます。
今、彼は翻訳者の謙虚な意見で悪く見えます。
おわりに
サービスは、Angularの最も魅力的な機能の1つです。 それらを作成するには多くの方法がありますが、私たちの場合に最適なものを選択するだけです