1、概述
依賴注入( Dependency Injection ) 簡稱DI
,是面向对象
設計中的一種设计原则
,用來減少程式碼之間的耦合度。 【相關教學推薦:《angular教學》】
class MailService { constructor(APIKEY) {} } class EmailSender { mailService: MailService constructor() { this.mailService = new MailService("APIKEY1234567890") } sendMail(mail) { this.mailService.sendMail(mail) } } const emailSender = new EmailSender() emailSender.sendMail(mail)
EmailSender 類別運行時要使用MailService 類,EmailSender 類別依賴MailService 類,MailService 類別是EmailSender 類別的依賴項。
以上寫法的耦合度太高,程式碼並不健壯。如果MailService 類別改變了參數的傳遞方式,在EmailSender 類別中的寫法也要跟著改變。
class EmailSender { mailService: MailService constructor(mailService: MailService) { this.mailService = mailService; } } const mailService = new MailService("APIKEY1234567890") const emailSender = new EmailSender(mailService)
在實例化EmailSender 類別時將它的依賴項透過constructor 建構函式參數的形式註入到類別的內部,而這種寫法就是依賴注入。
透過依賴注入降了程式碼之間的耦合度,增加了程式碼的可維護性。 MailService 類別中程式碼的變更再也不會影響EmailSender 類別。
2、DI 框架
Angular 有自己的DI 框架
,它將實作依賴注入的過程隐藏
了,對於開發者來說只需使用很簡單的程式碼就可以使用複雜的依賴注入功能。
在Angular 的DI 框架中有四個核心概念:
Dependency
:組件要依賴的實例對象,服務實例對象
Token
:獲取服務實例對象的標識
Injector
:注入器,負責创建维护
服務類的實例對象並向組件中注入
服務實例物件(管理服務物件的建立和取得)。
Provider
:配置注入器的對象,指定建立服務實例對象的服務類別和取得實例對象的識別。 (Provider:提供者)
注入器負責建立服務類別實例對象,並將服務類別實例物件注入到需要的元件中。
建立注入器
import { ReflectiveInjector } from "@angular/core" // 服務類別class MailService {} // 建立注入器並傳入服務類別const injector = ReflectiveInjector.resolveAndCreate([MailService])
取得注入器中的服務類別實例物件
const mailService = injector.get(MailService)
服務實例物件為單例模式,注入器在建立服務實例後會對其進行快取
const mailService1 = injector.get(MailService) const mailService2 = injector.get(MailService) console.log(mailService1 === mailService2) // true
不同的注入器傳回不同的服務實例物件
const injector = ReflectiveInjector.resolveAndCreate([MailService]) const childInjector = injector.resolveAndCreateChild([MailService]) const mailService1 = injector.get(MailService) const mailService2 = childInjector.get(MailService) console.log(mailService1 === mailService2) // false
服務實例的查找類似函數作用域链
,當前級別可以找到就使用當前級別,當前級別找不到去父級中查找
const injector = ReflectiveInjector.resolveAndCreate([ MailService]) const childInjector = injector.resolveAndCreateChild([]) const mailService1 = injector.get(MailService) const mailService2 = childInjector.get(MailService) console.log(mailService1 === mailService2) // true
配置注入器的對象,指定了建立實例對象的服務類別和存取服務實例對象的識別。
const injector = ReflectiveInjector.resolveAndCreate([ { provide: MailService, useClass: MailService } ])
存取依賴物件的識別也可以是字串類型
const injector = ReflectiveInjector.resolveAndCreate([ { provide: "mail", useClass: MailService } ]) const mailService = injector.get("mail")
useValue
const injector = ReflectiveInjector.resolveAndCreate([ { provide: "Config", useValue: Object.freeze({ APIKEY: "API1234567890", APISCRET: "500-400-300" }) } ]) const Config = injector.get("Config")
將實例物件和外部的參考建立了鬆散耦合關係,外部透過識別獲取實例對象,只要標識保持不變,內部代碼怎麼變都不會影響到外部。