您好,登錄后才能下訂單哦!
這篇文章主要介紹“VSCode中依賴注入的原理是什么”,在日常操作中,相信很多人在VSCode中依賴注入的原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”VSCode中依賴注入的原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
假設以下情況:
服務模塊 A,依賴服務 B;
服務模塊 B;
功能模塊 Feature,依賴服務 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();
代碼簡單明了,存在一些問題,比如:如果 A 和 Feature 依賴的 B 需要是同一個實例,以上的寫法將會初始化兩個 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);
某個模塊初始化時,先在外部將其所依賴的模塊創建出來,通過參數的形式傳入功能模塊。這樣的寫法就是「依賴注入」。
現在這種寫法的問題在于:手動傳參的形式,必須人工保證 new 的順序,即必須獲得 a, b 實例才能執行 new Feature。
當依賴關系變得復雜時,創建一個功能模塊之前很有可能需要無數個基礎模塊,這時候復雜度將會非常高。
想象一種模式:存在一個模塊控制器,或者說「服務管理器」來管理這些依賴關系:
class Feature {
// 聲明這個模塊依賴 idA, idB
idA
idB
}
// 告知「服務管理器」,怎么找對應的模塊
services[idA] = A;
services[idB] = B;
// 使用時
const feature = services.createInstance(Feature);
這個 services 承載的不就是之前的「手工」過程嗎?
在 createInstance(Feature) 時,分析 Feature 所依賴的模塊:
如果所依賴的模塊還未創建出實例,遞歸創建出該服務實例,最終返回;
如果所依賴的模塊已有實例,返回該實例;
找齊后通過參數注入 Feature,完成初始化;
VSCode 實現的正是這么一套「依賴注入體系」。
要實現這樣一套功能,大致需要:
一個類如何聲明其依賴的服務 id,即給定一個 類,外部如何知道他依賴了哪些服務?
如何管理管理服務?
如何創建某個模塊?
下文會實現一個最簡單的模型,涵蓋主體流程。
如何給一個 類 打上烙印,聲明它所依賴的服務呢?
將問題再次抽象:如何給一個類加上額外的信息?
其實,每個類在 es5 下都是 Function,而每個 Function 說到底也只是 Object ,只要給 Object 加上幾個字段來標識所需要的服務 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 }]
通過這種方式,通過 Feature (之后會稱之為 構造器 ctor)就可以獲取到 serviceId。
使用 Map 來進行管理,一個 id 對應一個 服務 ctor。
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);
現在,就可以通過 Feature 來找到所依賴的服務的構造器了
// 通過 Feature 找到所依賴的 A
const serviceId = Feature['deps'][0].id; // idA
console.log(
'Feature.deps',
services.get(serviceId) // A
);
具體思路為:
如果所依賴的模塊還未創建出實例,遞歸創建出該服務實例,最終返回;
如果所依賴的模塊已有實例,返回該實例;
找齊后通過參數注入 Feature,完成初始化;
這里先上一個簡單的 demo,只有一層的依賴(即所依賴的服務沒有依賴其他服務),簡單的講,就是沒有遞歸能力:
class InstantiationService {
services: ServiceCollection;
constructor(services: ServiceCollection) {
this.services = services;
}
createInstance(ctor: any) {
// 1. 獲取 ctor 依賴的 服務id
// 結果為: ['idA']
const depIds = ctor['deps'].map((item: any) => item.id);
// 2. 獲取服務 id 對應的 服務構造器
// 結果為:[A]
const depCtors = depIds.map((id: string) => services.get(id));
// 3. 獲取服務實例
// 結果為: [ A { name: 'a'} ]
const args = depCtors.map((ctor: any) => new ctor());
// 4. 依賴的服務作為參數注入,實例化所需要模塊
// 結果為:[ Feature { name: 'feature', a }]
const result = new ctor(...args);
return result;
}
}
const instantiation = new InstantiationService(services);
// 使用時
const feature = instantiation.createInstance(Feature);
要使用 Feature 時,只需要調用 createInstance,不用管他所依賴的服務是否被初始化,instantiation 幫我們做了這個事情。
到此,關于“VSCode中依賴注入的原理是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。