この記事では、VSCode における依存関係注入の原理を簡単に分析します。依存関係注入が何を行うかについて話しましょう。依存性注入を行うにはどうすればよいですか?お役に立てれば幸いです!
チームはしばらく「Dependency Injection」を実装してきましたが、使用するたびに違和感を感じます。常に不明瞭な概念がたくさんあります: サービス ID 、サービス説明シンボル、サービス デコレータなど。
原理が理解できていないからか、使っていると「仮想的」に感じてしまうのですが、最近VS Codeのソースコードやチームリーダーの共有記事を読んで原理を明確にしてみました。 . Here's what I do コアロジックの簡単な紹介。
次の状況を想定します。
サービス モジュール A、依存サービス B。
class B {} class A { constructor() { // 在 A 的构造器中 new B this.b = new B(); } } class Feature { constructor() { this.a = new A(); this.b = new B(); } } // 使用时 const feature = new Feature();
コードは単純明快ですが、いくつか問題があります。たとえば、Feature が依存する A と B が同じインスタンスである必要がある場合、上記の書き込みメソッドは 2 つの B インスタンスを初期化します。 [推奨学習:
vscode チュートリアル、プログラミング教育 ]簡単な変更:
class A { constructor(b: B) { this.b = b; } } class Feature { constructor(a, b) { this.a = a; this.b = b; } } // 使用时 const b = new B(); const a = new A(b); const feature = new Feature(a, b);
モジュールが初期化されるとき、まず外部から依存するモジュールは次のとおりです。作成され、パラメータの形式で汎用モジュールに渡されます。この書き方は「
Dependency Injection」です。 この書き方の問題は、手動パラメータ転送の形式では、new の順序を手動で保証する必要があること、つまり、new を実行する前に a と b のインスタンスを取得する必要があることです。 特徴。
依存関係が複雑になると、機能モジュールを作成する前に無数の基本モジュールが必要になる可能性があり、非常に複雑になります。この感覚に似ています:
モデルを想像してください: これらの依存関係を管理するモジュール コントローラー、または「サービス マネージャー」があります:
class Feature { // 声明这个模块依赖 idA, idB idA idB } // 告知「服务管理器」,怎么找对应的模块 services[idA] = A; services[idB] = B; // 使用时 const feature = services.createInstance(Feature);
Isn'tこのサービスは以前の「手動」プロセスを実行しますか?
createInstance(Feature) の場合、Feature が依存するモジュールを分析します:依存関係情報の追加
実際、es5 ではすべてのクラスが関数であり、最終的には各関数は単なるオブジェクトです。必要なサービス ID を識別するためにオブジェクトにいくつかのフィールドを追加する限り、次の作業を完了できます。必要なもの、機能。 これは、「パラメータ デコレータ」を記述することで簡単に実行できます:
// 参数装饰器 const decorator = ( target: Object, // 被装饰的目标,这里为 Feature propertyName: string, index: number // 参数的位置索引 ) => { target['deps'] = [{ index, id: 'idA', }]; } class Feature { name = 'feature'; a: any; constructor( // 参数装饰器 @decorator a: any, ) { this.a = a; } } console.log('Feature.deps', Feature['deps']); // [{ id: 'idA', index: 0 }]
サービス管理
class A { name = 'a'; } // 服务集 class ServiceCollection { // 服务集合 // key 为服务标识 // value 为 服务ctor private entries = new Map<string, any>(); set(id: string, ctor: any) { this.entries.set(id, ctor); } get(id: string): any { return this.entries.get(id); } } const services = new ServiceCollection(); // 声明服务 A id 为 idA services.set('idA', A);
これで、Feature
// 通过 Feature 找到所依赖的 A const serviceId = Feature['deps'][0].id; // idA console.log( 'Feature.deps', services.get(serviceId) // A );
#依存モジュールがまだインスタンスを作成していない場合は、サービス インスタンスを再帰的に作成し、最後に戻ります。
依存するモジュールにすでにインスタンスがある場合は、そのインスタンスを返します。
class InstantiationService { services: ServiceCollection; constructor(services: ServiceCollection) { this.services = services; } createInstance(ctor: any) { // 1. 获取 ctor 依赖的 服务id // 结果为: ['idA'] const depIds = ctor['deps'].map((item: any) => item.id); // 2. 获取服务 id 对应的 服务构造器 // 结果为:[A] const depCtors = depIds.map((id: string) => services.get(id)); // 3. 获取服务实例 // 结果为: [ A { name: 'a'} ] const args = depCtors.map((ctor: any) => new ctor()); // 4. 依赖的服务作为参数注入,实例化所需要模块 // 结果为:[ Feature { name: 'feature', a }] const result = new ctor(...args); return result; } } const instantiation = new InstantiationService(services); // 使用时 const feature = instantiation.createInstance(Feature);
この記事では、デモレベルの「依存関係注入」モデルを簡単に実装し、次のことを簡単に実装します。
モジュールに必要なもの宣言 依存関係;
サービス管理;
モジュール作成;
これに基づいて、いくつかの高度な機能を拡張できます:
モジュール作成 (再帰的): VSCode はスタック ダイアグラムを使用してこれを実行し、アルゴリズムは複雑ではありません。 ##依存関係の収集: 各モジュールの依存関係を分析するために使用でき、「循環依存関係」があるかどうかを検出できます。
ソース コード アドレス
この記事のコードはこちらを参照してください。 依存関係注入システム全体については、VSCode によって記述されたコードを参照してください。高度な情報については、ここを参照してください。 参考資料
VS コードのソース コードの場所: src/vs/platform/instantiation/commonこの記事はコードのアイデアに基づいており、命名も非常に一貫しています (manual Dog head)
#!!
以上がVSCode の依存関係注入の原理について簡単に説明します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。