溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

VSCode中依賴注入的原理是什么

發(fā)布時(shí)間:2023-02-08 09:14:53 來(lái)源:億速云 閱讀:104 作者:iii 欄目:軟件技術(shù)

這篇文章主要介紹“VSCode中依賴注入的原理是什么”,在日常操作中,相信很多人在VSCode中依賴注入的原理是什么問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”VSCode中依賴注入的原理是什么”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

依賴注入做了什么

假設(shè)以下情況:

  • 服務(wù)模塊 A,依賴服務(wù) B;

  • 服務(wù)模塊 B;

  • 功能模塊 Feature,依賴服務(wù) A 和 B;

按照普通的寫(xiě)法就是:

class B {}

class A {
    constructor() {
        // 在 A 的構(gòu)造器中 new B
        this.b = new B();
    }
}

class Feature {
    constructor() {
        this.a = new A();
        this.b = new B();
    }
}

// 使用時(shí)
const feature = new Feature();

代碼簡(jiǎn)單明了,存在一些問(wèn)題,比如:如果 A 和 Feature 依賴的 B 需要是同一個(gè)實(shí)例,以上的寫(xiě)法將會(huì)初始化兩個(gè) B 實(shí)例?!就扑]學(xué)習(xí):vscode教程、編程教學(xué)】

簡(jiǎn)單修改一下:

class A {
    constructor(b: B) {
        this.b = b;
    }
}

class Feature {
    constructor(a, b) {
        this.a = a;
        this.b = b;
    }
}

// 使用時(shí)
const b = new B();
const a = new A(b);
const feature = new Feature(a, b);

某個(gè)模塊初始化時(shí),先在外部將其所依賴的模塊創(chuàng)建出來(lái),通過(guò)參數(shù)的形式傳入功能模塊。這樣的寫(xiě)法就是「依賴注入」。

現(xiàn)在這種寫(xiě)法的問(wèn)題在于:手動(dòng)傳參的形式,必須人工保證 new 的順序,即必須獲得 a, b 實(shí)例才能執(zhí)行 new Feature。

當(dāng)依賴關(guān)系變得復(fù)雜時(shí),創(chuàng)建一個(gè)功能模塊之前很有可能需要無(wú)數(shù)個(gè)基礎(chǔ)模塊,這時(shí)候復(fù)雜度將會(huì)非常高。

想象一種模式:存在一個(gè)模塊控制器,或者說(shuō)「服務(wù)管理器」來(lái)管理這些依賴關(guān)系:

class Feature {
    // 聲明這個(gè)模塊依賴 idA, idB
    idA
    idB
}

// 告知「服務(wù)管理器」,怎么找對(duì)應(yīng)的模塊
services[idA] = A;
services[idB] = B;

// 使用時(shí)
const feature = services.createInstance(Feature);

這個(gè) services 承載的不就是之前的「手工」過(guò)程嗎?
在 createInstance(Feature) 時(shí),分析 Feature 所依賴的模塊:

  • 如果所依賴的模塊還未創(chuàng)建出實(shí)例,遞歸創(chuàng)建出該服務(wù)實(shí)例,最終返回;

  • 如果所依賴的模塊已有實(shí)例,返回該實(shí)例;

  • 找齊后通過(guò)參數(shù)注入 Feature,完成初始化;
    VSCode 實(shí)現(xiàn)的正是這么一套「依賴注入體系」。

依賴注入怎么做?

要實(shí)現(xiàn)這樣一套功能,大致需要:

  • 一個(gè)類如何聲明其依賴的服務(wù) id,即給定一個(gè) 類,外部如何知道他依賴了哪些服務(wù)?

  • 如何管理管理服務(wù)?

  • 如何創(chuàng)建某個(gè)模塊?

下文會(huì)實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的模型,涵蓋主體流程。

添加依賴信息

如何給一個(gè) 類 打上烙印,聲明它所依賴的服務(wù)呢?
將問(wèn)題再次抽象:如何給一個(gè)類加上額外的信息?
其實(shí),每個(gè)類在 es5 下都是 Function,而每個(gè) Function 說(shuō)到底也只是 Object ,只要給 Object 加上幾個(gè)字段來(lái)標(biāo)識(shí)所需要的服務(wù) id,就可以完成所需要的功能。
通過(guò) 「參數(shù)裝飾器」的寫(xiě)法,可以很容易做到這一點(diǎn):

// 參數(shù)裝飾器 
const decorator = (
    target: Object, // 被裝飾的目標(biāo),這里為 Feature
    propertyName: string, 
    index: number // 參數(shù)的位置索引
) => {
    target['deps'] = [{        index,        id: 'idA',    }];
}
class Feature {
    name = 'feature';
    a: any;
    constructor(
        // 參數(shù)裝飾器
        @decorator a: any,
    ) {
        this.a = a;
    }
}
console.log('Feature.deps', Feature['deps']);
// [{ id: 'idA', index: 0 }]

通過(guò)這種方式,通過(guò) Feature (之后會(huì)稱之為 構(gòu)造器 ctor)就可以獲取到 serviceId。

服務(wù)管理

使用 Map 來(lái)進(jìn)行管理,一個(gè) id 對(duì)應(yīng)一個(gè) 服務(wù) ctor。

class A {
    name = 'a';
}

// 服務(wù)集
class ServiceCollection {
    // 服務(wù)集合
    // key 為服務(wù)標(biāo)識(shí)
    // value 為 服務(wù)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();

// 聲明服務(wù) A id 為 idA
services.set('idA', A);

現(xiàn)在,就可以通過(guò) Feature 來(lái)找到所依賴的服務(wù)的構(gòu)造器了

// 通過(guò) Feature 找到所依賴的 A
const serviceId = Feature['deps'][0].id; // idA
console.log(
    'Feature.deps', 
    services.get(serviceId) // A
);

模塊創(chuàng)建

具體思路為:

  • 如果所依賴的模塊還未創(chuàng)建出實(shí)例,遞歸創(chuàng)建出該服務(wù)實(shí)例,最終返回;

  • 如果所依賴的模塊已有實(shí)例,返回該實(shí)例;

  • 找齊后通過(guò)參數(shù)注入 Feature,完成初始化;

這里先上一個(gè)簡(jiǎn)單的 demo,只有一層的依賴(即所依賴的服務(wù)沒(méi)有依賴其他服務(wù)),簡(jiǎn)單的講,就是沒(méi)有遞歸能力:

class InstantiationService {
    services: ServiceCollection;

    constructor(services: ServiceCollection) {
        this.services = services;
    }

    createInstance(ctor: any) {
        // 1. 獲取 ctor 依賴的 服務(wù)id
        // 結(jié)果為: ['idA']
        const depIds = ctor['deps'].map((item: any) => item.id);

        // 2. 獲取服務(wù) id 對(duì)應(yīng)的 服務(wù)構(gòu)造器
        // 結(jié)果為:[A]
        const depCtors = depIds.map((id: string) => services.get(id));

        // 3. 獲取服務(wù)實(shí)例
        // 結(jié)果為: [ A { name: 'a'} ]
        const args = depCtors.map((ctor: any) => new ctor());

        // 4. 依賴的服務(wù)作為參數(shù)注入,實(shí)例化所需要模塊
        // 結(jié)果為:[ Feature { name: 'feature', a }]
        const result = new ctor(...args);

        return result;
    }
}

const instantiation = new InstantiationService(services);

// 使用時(shí)
const feature = instantiation.createInstance(Feature);

要使用 Feature 時(shí),只需要調(diào)用 createInstance,不用管他所依賴的服務(wù)是否被初始化,instantiation 幫我們做了這個(gè)事情。

到此,關(guān)于“VSCode中依賴注入的原理是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI