Maison  >  Article  >  outils de développement  >  Parlons brièvement du principe de l'injection de dépendances dans VSCode

Parlons brièvement du principe de l'injection de dépendances dans VSCode

青灯夜游
青灯夜游avant
2023-02-07 18:18:482065parcourir

Cet article vous donnera une brève analyse du principe de l'injection de dépendances dans VSCode. Parlons de ce que fait l'injection de dépendances ? Comment faire une injection de dépendances ? J'espère que cela aidera tout le monde !

Parlons brièvement du principe de l'injection de dépendances dans VSCode

L'équipe fait la promotion de "l'injection de dépendances" depuis un certain temps, mais à chaque fois qu'elle est utilisée, cela semble étrange. Il existe de nombreux concepts qui ne sont toujours pas clairs : identifiant de service, descripteur de service, décorateur de service, etc.

C'est peut-être parce que je ne comprends pas les principes et que cela semble « virtuel » lorsque je l'utilise. Récemment, j'ai essayé de clarifier les principes en lisant le code source de VS Code et les articles partagés par les chefs d'équipe. Introduction logique de base.

Que fait l'injection de dépendances

Supposons la situation suivante :

  • Module de service A, dépendant du service B 

  • Module de service B 

  • Module de fonction Fonctionnalité, dépendant des services A et B ;

Selon la méthode d'écriture ordinaire, c'est :

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

Le code est simple et clair, mais il y a quelques problèmes. Par exemple : si A et B dont dépend cette fonctionnalité doivent être la même instance, la méthode d'écriture ci-dessus initialisera deux instances B. [Apprentissage recommandé : Tutoriel vscode, Enseignement de la programmation]

Modification simple :

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

Lors de l'initialisation d'un module, les modules dont il dépend sont d'abord créés en externe et transmis au module fonction sous forme de paramètres. Cette façon d'écrire est "Dependency Injection".

Le problème avec cette façon d'écrire maintenant est que sous forme de transfert manuel de paramètres, l'ordre de new doit être garanti manuellement, c'est-à-dire que les instances de a et b doivent être obtenues avant que new puisse être exécuté. Fonctionnalité.

Lorsque les dépendances deviennent complexes, il est probable que d'innombrables modules de base soient nécessaires avant de créer un module fonctionnel, et la complexité sera très élevée à ce moment-là. Similaire à ce sentiment :

Parlons brièvement du principe de linjection de dépendances dans VSCode

Imaginez un modèle : il existe un contrôleur de module, ou "gestionnaire de services" pour gérer ces dépendances :

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

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

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

Ce service ne porte-t-il pas le processus "manuel" précédent ?
Lorsque createInstance(Feature), analysez les modules dont Feature dépend :

  • Si le module dont il dépend n'a pas créé d'instance, créez récursivement l'instance de service et retournez enfin

  • Si le module dont il dépend ; on n'a pas créé d'instance, S'il y a une instance, renvoyez l'instance ;

  • Après avoir tout trouvé, injectez Feature via les paramètres pour terminer l'initialisation
    VSCode implémente exactement un tel "système d'injection de dépendances".

Comment faire une injection de dépendance ?

Pour implémenter un tel ensemble de fonctions, vous avez en gros besoin de :

  • Comment une classe déclare-t-elle les identifiants de service dont elle dépend ? Autrement dit, étant donné une classe, comment l'extérieur sait-il de quels services elle dépend ?

  • Comment gérer les services de gestion ?

  • Comment créer un module ?

Ce qui suit mettra en œuvre le modèle le plus simple, couvrant le processus principal.

Ajouter des informations sur les dépendances

Comment marquer une classe et déclarer les services dont elle dépend ?
Résumez à nouveau le problème : Comment ajouter des informations supplémentaires à un cours ?
En fait, chaque classe est une fonction sous es5, et chaque fonction n'est qu'un objet en dernière analyse. Tant que quelques champs sont ajoutés à l'objet pour identifier l'identifiant de service requis, les fonctions requises peuvent être complétées.
Cela peut être facilement fait en écrivant le "Parameter Decorator":

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

De cette façon, le serviceId peut être obtenu via Feature (qui sera appelé constructeur ctor plus tard).

Gestion des services

Utilisez Map pour la gestion, un identifiant correspond à un cteur de service.

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

Le schéma schématique est le suivant :

Maintenant, vous pouvez trouver le constructeur du service dépendant via la fonctionnalité

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

Création de module

L'idée spécifique est :

  • Si le module dépendant has still Si aucune instance n'est créée, l'instance de service sera créée de manière récursive et finalement renvoyée

  • Si le module dont il dépend a déjà une instance, renvoyez l'instance

  • Après avoir tout trouvé, injectez Feature via les paramètres ; pour terminer l'initialisation ;

Voici une démo simple, avec une seule couche de dépendances (c'est-à-dire que les services dépendants ne dépendent pas d'autres services). À ce stade, le processus principal d'injection de dépendances a été implémenté et Feature doit être utilisé, il suffit d'appeler createInstance, que les services dont il dépend aient été initialisés ou non, l'instanciation le fait pour nous.

Résumé

Cet article implémente simplement un modèle « d'injection de dépendances » de niveau démo, qui implémente simplement :

  • la déclaration des dépendances requises

  • la gestion des services ;

  • Sur cette base, certaines fonctions avancées peuvent être étendues :
  • Création de modules (récursifs) : VSCode utilise stack + graph pour ce faire, et l'algorithme n'est pas compliqué

    Collection de dépendances : peut être utilisé Analyser le les dépendances de chaque module et détecter s'il existe des "dépendances cycliques" ;
  • Destruction du module : lorsque le module est détruit, détruisez récursivement les instances de service dont il dépend
  • Initialisation paresseuse : lors de la création de services dépendants, choisissez de ; créez un proxy, et l'instance ne sera créée que lorsqu'elle sera réellement utilisée ;
  • Dépendance asynchrone : Comment exécuter la logique de création lorsque le processus de création du service dépendant est asynchrone
  • Adresse du code source

    ; Voir le code de cet article ici.

  • Fonctions complètes
Reportez-vous au code écrit par l'ensemble du système d'injection de dépendances de VSCode Pour des informations avancées, vous pouvez voir ici.

Matériaux de référence
Emplacement du code source du code VS : src/vs/platform/instantiation/commonCet article s'appuie sur des idées de code et le nom est également très cohérent (tête de chien manuelle

Pour plus de connaissances sur VSCode, veuillez visiter :

Tutoriel vscode

!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer