依賴注入是一種設計思想,並非某一類語言所特有的,所以能夠參考開濤大神關於學習Java語言的Spring框架
時對其的解釋:html
DI—Dependency Injection,即「依賴注入」:是組件之間依賴關係由容器在運行期決定,形象的說,即由容器動態的將某個依賴關係注入到組件之中。依賴注入的目的並不是爲軟件系統帶來更多功能,而是爲了提高組件重用的頻率,併爲系統搭建一個靈活、可擴展的平臺。經過依賴注入機制,咱們只須要經過簡單的配置,而無需任何代碼就可指定目標須要的資源,完成自身的業務邏輯,而不須要關心具體的資源來自何處,由誰實現。
理解DI的關鍵是:「誰依賴誰,爲何須要依賴,誰注入誰,注入了什麼」,那咱們來深刻分析一下:segmentfault
IoC和DI由什麼關係呢?其實它們是同一個概念的不一樣角度描述,因爲控制反轉概念比較含糊(可能只是理解爲容器控制對象這一個層面,很難讓人想到誰來維護對象關係),因此2004年大師級人物Martin Fowler又給出了一個新的名字:「依賴注入」,相對IoC 而言,「依賴注入」明確描述了「被注入對象依賴IoC容器配置依賴對象」。 1數組
Angular中能夠在app.module.ts
中進行全局聲明,也能夠在組件內部根據特定需求實現特定聲明。
聲明是經過屬性providers
實現的,顧名思義,它是一個對象提供者,複數形式表名其爲數組形式。且子類型爲Provide
,它位於@angular/core
中,實現以下:app
export interface TypeProvider extends Type<any> { } export interface ValueProvider { provide: any; useValue: any; multi?: boolean; } export interface ClassProvider { provide: any; useClass: Type<any>; multi?: boolean; } export interface ExistingProvider { provide: any; useExisting: any; multi?: boolean; } export interface FactoryProvider { provide: any; useFactory: Function; deps?: any[]; multi?: boolean; } export declare type Provider = TypeProvider | ValueProvider | ClassProvider | ExistingProvider | FactoryProvider | any[];
能夠看到,Provider
共有5個明確的子類,也決定了其使用方式的數量。因爲全局聲明和組件內部聲明的方式差異不大,可見的區別是在app.module.ts
中屬性providers
是在模塊註解@NgModule
中聲明而組件中是經過註解@Component
聲明。所以實現方式不對全局和組件加以區分。框架
因爲是初學,此處僅列舉經常使用的幾種方式:useClass
、useFactory
和useValue
。dom
providers: [{provide: DefaultBookService, useClass: DefaultBookService}]
其中provide
定義了token
,而useClass
則指明瞭使用的類,此處因爲token
和實現類相同,均爲DefaultBookService
所以能夠簡寫爲providers: [DefaultBookService]
。ide
providers: [{ provide: DefaultBookService, useFactory: () => { const rdm = Math.random() < 0.5; if (rdm) { return new DefaultBookService(); } else { return new HuaZhangBookService(); } }
HuaZhangBookService
是DefaulteBookService
的一個子類。根據狀況返回所需注入的對象。函數
若是經過依賴注入的對象同時依賴另外一個經過依賴注入的對象應如何實現呢?好比DefaultBookService
,它的構造函數爲:
constructor(public logger: LoggerService) { }
,而LoggerService也是經過依賴注入-即不須要本身手工new LoggerService()
-時應該怎麼辦?在類FactoryProvider
中提供了一個名叫deps
的參數,它能夠幫助咱們實現依賴對象的引用。用法以下:學習
providers: [{ provide: DefaultBookService, useFactory: (logger: LoggerService) => { const rdm = Math.random() < 0.5; if (rdm) { return new DefaultBookService(logger); } else { return new HuaZhangBookService(logger); } }, deps: [LoggerService] }, LoggerService]
deps
是一個任意類型的數組,爲何呢,由於類的參數不會只有一個,當構造方法中有多個參數時,可同時依賴多個不一樣類型的對象。this
基本用法:
{provide: 'IS_DEV_ENV', useValue: Math.random() < 0.5}
擴展用法:
providers: [{ provide: DefaultBookService, useFactory: (logger: LoggerService, isDev) => { if (isDev) { return new DefaultBookService(logger); } else { return new HuaZhangBookService(logger); } }, deps: [LoggerService, 'IS_DEV_ENV'] }, LoggerService, {provide: 'IS_DEV_ENV', useValue: Math.random() < 0.5} ]
能夠看到,在useFactory
的箭頭表達式中有兩個參數,他們依次對應deps
中的token
,即isDev對應token爲IS_DEV_ENV
的對象,而它正是使用了本小節中所涉及的useValue
形式,它返回一個boolean
對象。
另外須要注意的是,token
不止能指定特定的類,也能夠指定特定的值。
參考
@Injectable
或其子類如@Component
修飾後,纔可以使用,建議不管是否使用依賴注入,都使用@Injectable
修飾。constructor(private bookService: DefaultBookService) { }
,此時,其餘方法中直接使用this.bookService
來調用DefaultBookService
中的方法了。Injector
來進行訪問,它位於@angular/core
包中,所以上面的構造方法能夠這樣聲明constructor(private injector: Injector) { }
,經過this.injector.get(DefaultBookService)
來獲取DefaultBookService
對象並調用其中的方法,但不建議這樣作,由於不如直接傳入所需對象來的明確。app.module.ts
中使用useFactory
而且使用箭頭表達式來實現時,註冊的組件會報錯,至今無解,相關問題已發至segmentFault,哪位大神若是知道,煩請告訴,跪謝。Token
的學習能夠參考Angular 4 依賴注入教程之八 InjectToken的使用若是想要更加深刻的瞭解IoC和DI,請參考大師級人物Martin Fowler的一篇經典文章《Inversion of Control Containers and the Dependency Injection pattern》,原文地址:http://www.martinfowler.com/articles/injection.html。↩