ServiceScope class
SharePoint Frameworkによって使用されるサービス ロケーター パターン。
注釈
ServiceScope は、コンポーネントが依存関係 ("サービス") を登録および使用し、さまざまな実装を異なるスコープに登録できるようにする正式な方法を提供します。 これにより、コンポーネントを拡張可能な方法で依存関係から切り離すことで、モジュール性が向上します。
たとえば、さまざまなコンポーネントが IPageManager インスタンスにアクセスする必要があるとします。 単に PageManager をシングルトン (つまりグローバル変数) にすることもできますが、2 つ目の PageManager インスタンスを必要とするポップアップ ダイアログを作成する必要がある場合など、これは機能しません。 より良い解決策は、それを必要とする各コンポーネントのコンストラクター パラメーターとして PageManager を追加することですが、これらのコンストラクターを呼び出すコードにも PageManager パラメーターが必要であるという問題に直ちに直面します。 このような依存関係が多いアプリケーションでは、多くのサブシステムを結び付けるビジネス ロジックは、最終的には、考えられるすべての依存関係のコンストラクター パラメーターを取得します。これは厄介です。 自然な解決策は、すべての依存関係を "ApplicationContext" のような名前のクラスに移動し、コンストラクター パラメーターとしてこれを渡すことです。 これにより、PageManager を必要とするクラスに渡すことができます。このクラスを必要としない中間クラスが煩雑になることはありません。 ただし、"ApplicationContext" には、多くの関連性のないものに対してハードコーディングされた依存関係が存在するという設計上の問題が残っています。 より柔軟なアプローチは、適切なルックアップ キー (ServiceKey) を知っているコンシューマー/プロバイダーの項目を検索できるディクショナリにすることです。 これは、従来の SharePoint の SPContext API で使い慣れた、一般的な "サービス ロケーター" 設計パターンです。
ServiceScope では、この考え方をさらに 2 つの重要な方法で取り上げ、最初にスコープ メカニズムを提供します。たとえば、2 つの異なるページがある場合は、それぞれが一意の PageManager インスタンスを提供しながら、他の一般的な依存関係を共有できます。 次に、ServiceKey が依存関係の既定の実装を提供できるようにします。 これは、モジュール型クライアント側環境での API の安定性にとって重要です。たとえば、アプリケーションのバージョン 2.0 で、バージョン 2.0 コンポーネントで使用される新しい IDiagnosticTracing インターフェイスが導入されたとします。 バージョン 2.0 コンポーネントが古い 1.0 アプリケーションによって読み込まれると、失敗します。 この問題は、各コンシューマーに不足している依存関係をチェックし、そのケースを処理するように要求することで解決できますが、多くのチェックが必要になります。 より良い解決策は、既定の実装が常に存在することを保証することです。おそらく単純な動作なので、コンポーネントは、consume() がコントラクトを実装するオブジェクトを常に返すと想定できます。
使用法: ServiceScope インスタンスは、ServiceScope.startNewRoot() または ServiceScope.startNewChild() を呼び出すことによって作成されます。 最初は "未完了" 状態であり、その間に provide() を呼び出してサービス キーを登録できますが、consume() は許可されません。 ServiceScope.finish() が呼び出されると、consume() が許可され、provide() が許可されなくなります。 これらのセマンティクスにより、ServiceScope.consume() は常に同じキーに対して同じ結果を返し、初期化の順序に依存しません。 また、無限ループを気にすることなく、循環依存関係をサポートすることもできます。 (循環依存関係は避けるのが最善ですが、調整なしでさまざまなサード パーティによって提供されたコンポーネントを操作する場合、保証するのは困難です)。間違いを避けるために、serviceScope.whenFinished() からコールバック内で常に consume() を呼び出すのが最善です。
コンストラクター
(constructor)(parent) |
|
メソッド
consume(service |
サービス スコープからサービスを使用します。 |
create |
これは、simpleServiceClass の新しいインスタンスを構築し、ServiceScope.provide() を呼び出して登録するのと同じ短縮形関数です。 |
create |
これは、指定された serviceKey の既定の実装を作成し、それを ServiceScope.provide() を呼び出すことで登録する、簡単な関数です。 |
finish() | サービス スコープの初期化シーケンスを完了します。 |
get |
現在の ServiceScope の親を返します。これがルート スコープの場合は未定義です。 |
provide(service |
新しいサービスをサービス スコープに追加します。 |
start |
現在のスコープの子である新しい ServiceScope を構築します。 |
start |
新しいルート レベルの ServiceScope を作成します。 ルート レベルのスコープのみが、ServiceKeys の既定の実装を自動作成できます。 |
when |
ServiceScope.finish() が完了するまで操作を延期します。 |
コンストラクターの詳細
(constructor)(parent)
ServiceScope
クラスの新しいインスタンスを構築します
protected constructor(parent: ServiceScope | undefined);
パラメーター
- parent
-
ServiceScope | undefined
メソッドの詳細
consume(serviceKey)
サービス スコープからサービスを使用します。
consume<T>(serviceKey: IServiceKey<T>): T;
パラメーター
- serviceKey
-
IServiceKey<T>
サービスを登録するために provide() が呼び出されたときに使用されたキー
戻り値
T
サービス インスタンス
注釈
コンポーネントは、依存関係を「利用」するために (つまり、serviceKey を検索して、登録されたサービス インスタンスを返すために)、この関数を呼び出す必要があります。 インスタンスが見つからない場合、既定のインスタンスが自動的に作成され、ルート ServiceScope に登録されます。
createAndProvide(serviceKey, simpleServiceClass)
これは、simpleServiceClass の新しいインスタンスを構築し、ServiceScope.provide() を呼び出して登録するのと同じ短縮形関数です。
createAndProvide<T>(serviceKey: IServiceKey<T>, simpleServiceClass: ServiceClass<T>): T;
パラメーター
- serviceKey
-
IServiceKey<T>
サービスを利用するために後で使用できるキー
- simpleServiceClass
-
ServiceClass<T>
構築される TypeScript クラス
戻り値
T
新しく構築された simpleServiceClass のインスタンス
createDefaultAndProvide(serviceKey)
これは、指定された serviceKey の既定の実装を作成し、それを ServiceScope.provide() を呼び出すことで登録する、簡単な関数です。
createDefaultAndProvide<T>(serviceKey: IServiceKey<T>): T;
パラメーター
- serviceKey
-
IServiceKey<T>
サービスを利用するために後で使用できるキー
戻り値
T
ServiceKey.defaultCreator を使用して作成されたサービス インスタンス
finish()
サービス スコープの初期化シーケンスを完了します。
finish(): void;
戻り値
void
注釈
ServiceScope が最初に開始されると、provide() が許可されているが、consume() が許可されていない "未完了" 状態になります。 finish() を呼び出した後、consume() は許可されますが、provide() は許可されません。
この形式は、バグにつながる可能性のある複雑な状況の数を防ぎます。 たとえば、Scope2 は Scope1 の子であり、Scope1 はインターフェイス A のインスタンス A1 を提供するとします。Scope2.provide() が A2 で呼び出される前に、Scope2 から A1 を (継承経由で) 使用した場合、Scope2.consume() の後続の呼び出しで前の呼び出しとは異なる結果が返される可能性があります。 この非確定性は、診断が困難な予測不可能な結果を引き起こす可能性があります。
getParent()
現在の ServiceScope の親を返します。これがルート スコープの場合は未定義です。
getParent(): ServiceScope | undefined;
戻り値
ServiceScope | undefined
親サービスのスコープ
provide(serviceKey, service)
新しいサービスをサービス スコープに追加します。
provide<T>(serviceKey: IServiceKey<T>, service: T): T;
パラメーター
- serviceKey
-
IServiceKey<T>
サービスを利用するために後で使用されるキー
- service
-
T
登録されているサービス インスタンス
戻り値
T
"service" パラメーターとして渡されたオブジェクトと同じ
注釈
ServiceScope.provide() は、現在のスコープの特定の serviceKey の実装と、ルート スコープの特定の rootServiceKey の実装を登録するために使用されます。 ServiceScope が "unfinished" 状態の場合 (つまり、finish() が呼び出される前) にのみ使用できます。
startNewChild()
現在のスコープの子である新しい ServiceScope を構築します。
startNewChild(): ServiceScope;
戻り値
新しく作成されたルートの ServiceScope
注釈
サービス スコープはツリー構造を形成します。サービスを使用するときに、キーが子スコープによって明示的に指定されていない場合は、親階層が参照されます。
startNewRoot()
新しいルート レベルの ServiceScope を作成します。 ルート レベルのスコープのみが、ServiceKeys の既定の実装を自動作成できます。
static startNewRoot(): ServiceScope;
戻り値
新しく作成されたルートの ServiceScope
whenFinished(callback)
ServiceScope.finish() が完了するまで操作を延期します。
whenFinished(callback: () => void): void;
パラメーター
- callback
-
() => void
ServiceScope.consume() を呼び出す必要があるコードのブロック。
戻り値
void
注釈
finish() が呼び出される前に ServiceScope.consume() を呼び出すとエラーになります。 このエラーからコンポーネントを保護する最も信頼性の高い方法は、whenFinished() コールバック内で consume() 呼び出しを実行することです。 サービス スコープが既に完了している場合、コールバックはすぐに実行されます。 それ以外の場合は、スコープがコールバック登録の順序で完了した後に実行されます
注: これは非同期コールバックではありません。 ServiceScope の初期化は通常、安価で有効期間が短いです。 ただし、制御フローは多くの場合、多数のコンストラクターと基底クラスを介してスレッドします。これは whenFinished() を使用して簡略化できます。