Heim  >  Artikel  >  Entwicklungswerkzeuge  >  Sprechen Sie kurz über das Prinzip der Abhängigkeitsinjektion in VSCode

Sprechen Sie kurz über das Prinzip der Abhängigkeitsinjektion in VSCode

青灯夜游
青灯夜游nach vorne
2023-02-07 18:18:482071Durchsuche

Dieser Artikel gibt Ihnen eine kurze Analyse des Prinzips der Abhängigkeitsinjektion in VSCode. Lassen Sie uns darüber sprechen, was die Abhängigkeitsinjektion bewirkt. Wie führt man eine Abhängigkeitsinjektion durch? Hoffe, es hilft allen!

Sprechen Sie kurz über das Prinzip der Abhängigkeitsinjektion in VSCode

Das Team fördert „Dependency Injection“ schon seit einiger Zeit, aber jedes Mal, wenn es verwendet wird, fühlt es sich seltsam an. Es gibt viele Konzepte, die immer unklar sind: Service-ID, Service-Deskriptor, Service-Dekorator usw.

Vielleicht liegt es daran, dass ich die Prinzipien nicht verstehe und es sich bei der Verwendung „virtuell“ anfühlt. Ich habe kürzlich versucht, die Prinzipien zu klären, indem ich den Quellcode von VS Code und die von Teamleitern geteilten Artikel gelesen habe Kern Logische Einführung.

Was bewirkt die Abhängigkeitsinjektion? Nehmen wir die folgende Situation an:

Dienstmodul A, abhängig von Dienst B;
  • Funktionsmodul Feature, abhängig von Dienst A und B;
  • Nach der normalen Schreibmethode ist es:
  • 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();
  • Der Code ist einfach und klar, aber es gibt einige Probleme: Wenn A und B von dieser Funktion abhängen, müssen sie dieselbe Instanz sein. Die obige Schreibmethode initialisiert zwei B-Instanzen. [Empfohlenes Lernen:

    vscode-Tutorial

    ,
  • Programmierlehre
]

Einfache Änderung:

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);
Bei der Initialisierung eines Moduls werden die Module, von denen es abhängt, zunächst extern erstellt und in Form von Parametern an das Funktionsmodul übergeben. Diese Schreibweise ist „Dependency Injection“.

Das Problem bei dieser Schreibweise besteht nun darin, dass bei der manuellen Parameterübertragung die Reihenfolge von new manuell garantiert werden muss, das heißt, Instanzen von a und b müssen abgerufen werden, bevor new ausgeführt werden kann. Besonderheit.

Wenn Abhängigkeiten komplex werden, sind wahrscheinlich unzählige Basismodule erforderlich, bevor ein Funktionsmodul erstellt wird, und die Komplexität wird zu diesem Zeitpunkt sehr hoch sein. Ähnlich wie dieses Gefühl:

Stellen Sie sich ein Modell vor: Es gibt einen Modulcontroller oder „Dienstmanager“, der diese Abhängigkeiten verwaltet:

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

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

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

Trägt dieser Dienst nicht den vorherigen „manuellen“ Prozess?

Wenn Sie eine Instanz erstellen (Feature), analysieren Sie die Module, von denen das Feature abhängt:

Sprechen Sie kurz über das Prinzip der Abhängigkeitsinjektion in VSCode

Wenn das Modul, von dem es abhängt, keine Instanz erstellt hat, erstellen Sie die Dienstinstanz rekursiv und kehren Sie schließlich zurück on hat keine Instanz erstellt. Wenn eine Instanz vorhanden ist, geben Sie die Instanz zurück.


Nachdem Sie alles gefunden haben, fügen Sie die Funktion über Parameter ein, um die Initialisierung abzuschließen.
    VSCode implementiert genau ein solches „Abhängigkeitsinjektionssystem“.
  • Wie führt man eine Abhängigkeitsinjektion durch?

  • Um einen solchen Funktionssatz zu implementieren, benötigen Sie ungefähr:

  • Wie deklariert eine Klasse die Dienst-IDs, von denen sie abhängt? Das heißt, wie weiß die Außenstehende bei einer gegebenen Klasse, von welchen Diensten sie abhängt?

Wie verwaltet man Verwaltungsdienste?

Wie erstelle ich ein Modul?
  • Im Folgenden wird das einfachste Modell implementiert, das den Hauptprozess abdeckt.
  • Abhängigkeitsinformationen hinzufügen

  • Wie brande ich eine Klasse und deklariere die Dienste, von denen sie abhängt?

    Zusammenfassen Sie das Problem noch einmal:

    Wie füge ich einer Klasse zusätzliche Informationen hinzu?
Tatsächlich ist jede Klasse eine Funktion unter es5, und jede Funktion ist letztendlich nur ein Objekt. Solange dem Objekt einige Felder hinzugefügt werden, um die erforderliche Dienst-ID zu identifizieren, kann die erforderliche Funktion abgeschlossen werden.

Dies kann einfach durch Schreiben des „Parameter Decorators“ erfolgen:

// 参数装饰器 
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 }]

Auf diese Weise kann die Service-ID über Feature (das später als Konstruktor ctor bezeichnet wird) abgerufen werden.

Dienstverwaltung


Verwenden Sie Karte für die Verwaltung, eine ID entspricht einem Dienstleiter.

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);

Das schematische Diagramm sieht wie folgt aus:

Jetzt können Sie den Konstruktor des abhängigen Dienstes über die Funktion finden
// 通过 Feature 找到所依赖的 A
const serviceId = Feature[&#39;deps&#39;][0].id; // idA
console.log(
    &#39;Feature.deps&#39;, 
    services.get(serviceId) // A
);

Modulerstellung

Die spezifische Idee ist:

Wenn das abhängige Modul Wenn noch keine Instanz erstellt wurde, wird die Dienstinstanz rekursiv erstellt und schließlich zurückgegeben.

Wenn das Modul, von dem es abhängt, bereits eine Instanz hat, geben Sie die Instanz zurück.

Nachdem Sie alle Funktionen gefunden haben, fügen Sie die Funktion ein durch die Parameter, um die Initialisierung abzuschließen;
  • Hier ist zunächst eine einfache Demo mit nur einer Ebene von Abhängigkeiten (das heißt, die abhängigen Dienste sind nicht von anderen Diensten abhängig, es gibt keine Rekursionsfunktion). :
  • 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);
  • An diesem Punkt ist der Kernprozess der Abhängigkeitsinjektion abgeschlossen und Feature muss verwendet werden. Wir müssen nur createInstance aufrufen. Unabhängig davon, ob die Dienste, von denen es abhängt, initialisiert wurden, erledigt die Instanziierung dies für uns.

    Zusammenfassung

    Dieser Artikel implementiert lediglich ein „Abhängigkeitsinjektions“-Modell auf Demoebene, das einfach Folgendes implementiert:

    • erforderliche Abhängigkeiten für die Moduldeklaration;

    • Modulerstellung;

    • Auf dieser Grundlage können einige erweiterte Funktionen erweitert werden:

    Modulerstellung (rekursiv): VSCode verwendet dazu Stapel + Diagramm, und der Algorithmus ist nicht kompliziert;

    • Abhängigkeitssammlung: kann zum Analysieren verwendet werden Abhängigkeiten jedes Moduls und erkennen, ob es „zyklische Abhängigkeiten“ gibt;

    • Modulzerstörung: Wenn das Modul zerstört wird, zerstören Sie rekursiv die Dienstinstanzen, von denen es abhängt;

    • Verzögerte Initialisierung: Wählen Sie beim Erstellen abhängiger Dienste Erstellen Sie einen Proxy, und die Instanz wird nur erstellt, wenn sie tatsächlich verwendet wird.

    • Asynchrone Abhängigkeit: So führen Sie die Erstellungslogik aus, wenn der Erstellungsprozess des abhängigen Dienstes asynchron ist.

    • Quellcodeadresse
    • Den Code dieses Artikels finden Sie hier.

    Vollständige Funktionen Weitere Informationen finden Sie im Code, der vom gesamten Abhängigkeitsinjektionssystem von VSCode geschrieben wurde.
    ReferenzmaterialienVS-Code-Quellcode-Speicherort: src/vs/platform/instantiation/common

    Dieser Artikel basiert auf Code-Ideen und die Benennung ist ebenfalls sehr konsistent (manueller Hundekopf

    Weitere Informationen zu VSCode finden Sie unter :

    vscode-Tutorial

    !

Das obige ist der detaillierte Inhalt vonSprechen Sie kurz über das Prinzip der Abhängigkeitsinjektion in VSCode. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen