昨天提到可以 InjectionToken 這個類別來建立一個 DI Token,而且也可以在建立 DI Token 的時候提供建立實體用的工廠方法,那如果要提供的實體有其他的相依關係時,該怎麼辦?
這就是今天要介紹的 Tip:在建立 Token 時的工廠方法提供相依物件!
延續昨天的架構,在實作 IMyService 介面的 MyService 類別上加入 MyDepService 類別,建立 MyService 與 MyDepService 的相依關係:
export interface IMyService {
print(): string;
}
export class MyService implements IMyService {
constructor(private readonly myDep: MyDepService) {}
print(): string {
return this.myDep.hello();
}
}
↑ Block 1
接著就可以建立一個帶有工廠方法的 InjectionToken 物件。建立工廠方法時,若要建立的物件需要其他相依性,就可以透過 inject 這個函式,請 Angular 從 injector 中取出相依物件的實體:
export const MY_SERVICE_TOKEN = new InjectionToken<IMyService>('My Service', {
providedIn: 'root',
factory: () => new MyService(inject(MyDepService))
});
↑ Block 2
透過 Block 2 的方式建立 InjectionToken 後,只要是使用 MY_SERVICE_TOKEN 注入,Angular 就會自動幫你處理 MyService 類別的相依性問題了。
這次因為好奇 inject 函式到底做了什麼,所以就來爬 code 了,首先它的實作如下:
export const inject = ɵɵinject;
export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>): T;
export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags): T|null;
export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>, flags = InjectFlags.Default): T|null {
return (_injectImplementation || injectInjectorOnly)(resolveForwardRef(token), flags);
}
想要知道 ɵɵinject 函式最後是使用 _injectImplementation 還是 injectInjectorOnly 來處理 MyDepService 可以按以下的順序來爬:
到最後實際呼叫 ɵɵinject 函式時,_injectImplementation 就會是 undefine 的狀態,所以自然而然就會使用 injectInjectorOnly 這個函式來取得 MyDepService 的實體,並注入到 MyService 的 constructor 囉!
以下按照入團順序列出我們團隊夥伴的系列文章!