ホームページ  >  記事  >  開発ツール  >  VSCode の依存関係注入の原理について簡単に説明します。

VSCode の依存関係注入の原理について簡単に説明します。

青灯夜游
青灯夜游転載
2023-02-07 18:18:482030ブラウズ

この記事では、VSCode における依存関係注入の原理を簡単に分析します。依存関係注入が何を行うかについて話しましょう。依存性注入を行うにはどうすればよいですか?お役に立てれば幸いです!

VSCode の依存関係注入の原理について簡単に説明します。

チームはしばらく「Dependency Injection」を実装してきましたが、使用するたびに違和感を感じます。常に不明瞭な概念がたくさんあります: サービス ID 、サービス説明シンボル、サービス デコレータなど。

原理が理解できていないからか、使っていると「仮想的」に感じてしまうのですが、最近VS Codeのソースコードやチームリーダーの共有記事を読んで原理を明確にしてみました。 . Here's what I do コアロジックの簡単な紹介。

依存性注入の機能

次の状況を想定します。

  • サービス モジュール A、依存サービス B。

  • #サービス モジュール B;

  • 関数モジュールの機能、サービス 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 のインスタンスを取得する必要があることです。 特徴。

依存関係が複雑になると、機能モジュールを作成する前に無数の基本モジュールが必要になる可能性があり、非常に複雑になります。この感覚に似ています:

VSCode の依存関係注入の原理について簡単に説明します。モデルを想像してください: これらの依存関係を管理するモジュール コントローラー、または「サービス マネージャー」があります:

class Feature {
    // 声明这个模块依赖 idA, idB
    idA
    idB
}

// 告知「服务管理器」,怎么找对应的模块
services[idA] = A;
services[idB] = B;

// 使用时
const feature = services.createInstance(Feature);

Isn'tこのサービスは以前の「手動」プロセスを実行しますか?

createInstance(Feature) の場合、Feature が依存するモジュールを分析します:


    依存モジュールがインスタンスを作成していない場合は、再帰的にサービス インスタンスを作成し、最後に戻ります;
  • 依存するモジュールにすでにインスタンスがある場合は、インスタンスを返します。
  • すべてを見つけた後、パラメーターを介して機能を挿入して、初期化;
  • VSCode はまさにそのような「依存性注入システム」を実装しています。


依存性注入を行うにはどうすればよいですか?

このような一連の関数を実装するには、大まかに次のようにします。

    クラスは、依存するサービス ID をどのように宣言しますか。つまり、クラスが指定された場合、外部はどうやって知るのでしょうか? 彼が依存しているサービスは何ですか?
  • #管理サービスを管理するにはどうすればよいですか?
  • モジュールを作成するにはどうすればよいですか?
  • 以下は、メインプロセスをカバーする最も単純なモデルを実装します。

依存関係情報の追加

クラスをブランド化し、それが依存するサービスを宣言するにはどうすればよいでしょうか? 問題を再度抽象化します:

追加情報をクラスに追加するにはどうすればよいですか?


実際、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 }]

このようにして、serviceId は、Feature (後でコンストラクタ ctor と呼ばれます) を通じて取得できます。

サービス管理

管理にはマップを使用します。1 つの ID が 1 つのサービス センターに対応します。
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(&#39;idA&#39;, A);

概略図は次のとおりです:

これで、Feature

// 通过 Feature 找到所依赖的 A
const serviceId = Feature[&#39;deps&#39;][0].id; // idA
console.log(
    &#39;Feature.deps&#39;, 
    services.get(serviceId) // A
);

# を通じて依存サービスのコンストラクターを見つけることができます。 # #モジュールの作成

具体的なアイデアは次のとおりです。

#依存モジュールがまだインスタンスを作成していない場合は、サービス インスタンスを再帰的に作成し、最後に戻ります。

  • 依存するモジュールにすでにインスタンスがある場合は、そのインスタンスを返します。

  • ##すべてを見つけた後、パラメーターを介して機能を注入します。初期化を完了します;

  • これは、依存関係のレイヤーが 1 つだけある単純なデモです (つまり、依存するサービスは他のサービスに依存しません)。再帰機能なし:

    class InstantiationService {
        services: ServiceCollection;
    
        constructor(services: ServiceCollection) {
            this.services = services;
        }
    
        createInstance(ctor: any) {
            // 1. 获取 ctor 依赖的 服务id
            // 结果为: [&#39;idA&#39;]
            const depIds = ctor[&#39;deps&#39;].map((item: any) => item.id);
    
            // 2. 获取服务 id 对应的 服务构造器
            // 结果为:[A]
            const depCtors = depIds.map((id: string) => services.get(id));
    
            // 3. 获取服务实例
            // 结果为: [ A { name: &#39;a&#39;} ]
            const args = depCtors.map((ctor: any) => new ctor());
    
            // 4. 依赖的服务作为参数注入,实例化所需要模块
            // 结果为:[ Feature { name: &#39;feature&#39;, a }]
            const result = new ctor(...args);
    
            return result;
        }
    }
    
    const instantiation = new InstantiationService(services);
    
    // 使用时
    const feature = instantiation.createInstance(Feature);

    これまでのところ、依存関係注入のコア プロセスは実装されています。Feature を使用する場合は、依存するサービスが初期化されているかどうかに関係なく、createInstance を呼び出すだけで済みます。インスタンス化がこれを行います。
  • 概要

    この記事では、デモレベルの「依存関係注入」モデルを簡単に実装し、次のことを簡単に実装します。

    • モジュールに必要なもの宣言 依存関係;

    • サービス管理;

    • モジュール作成;

    これに基づいて、いくつかの高度な機能を拡張できます:

    • モジュール作成 (再帰的): VSCode はスタック ダイアグラムを使用してこれを実行し、アルゴリズムは複雑ではありません。 ##依存関係の収集: 各モジュールの依存関係を分析するために使用でき、「循環依存関係」があるかどうかを検出できます。

    • ##モジュールの破棄: モジュールが破棄されると、サービスは依存するインスタンスは再帰的に破棄されます;

    • 初期化の遅延: 依存サービスを作成するときに、プロキシの作成を選択すると、インスタンスは実際に使用されるときにのみ作成されます;

    • 非同期依存関係: 依存サービスの作成プロセスが非同期である場合に作成ロジックを実行する方法;

    • ソース コード アドレス

      この記事のコードはこちらを参照してください。
    完全な関数

    依存関係注入システム全体については、VSCode によって記述されたコードを参照してください。高度な情報については、ここを参照してください。 参考資料
    VS コードのソース コードの場所: src/vs/platform/instantiation/commonこの記事はコードのアイデアに基づいており、命名も非常に一貫しています (manual Dog head)

    VSCode の詳細については、次を参照してください:

    vscode チュートリアル

    #!!

以上がVSCode の依存関係注入の原理について簡単に説明します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。