Maison > Article > outils de développement > Parlons brièvement du principe de l'injection de dépendances dans VSCode
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 !
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.
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 :
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".
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.
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).
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('idA', 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['deps'][0].id; // idA console.log( 'Feature.deps', services.get(serviceId) // A );
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.
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 ;
; Voir le code de cet article 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
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!