這篇文章帶大家了解一下依賴注入,介紹一下依賴注入解決的問題和它原生的寫法是什麼,並聊聊Angular的依賴注入框架,希望對大家有所幫助!
最近在Angular專案中經常能碰到依賴注入這個關鍵字,但是始終不理解它是怎麼實現的,在Angular的官網上也只有關於它的使用,詳細點的原理並沒有說明,所以就下來我們就從原生的寫法來講解一下,依賴注入是用來解決什麼問題的,他用js應該怎麼去表現。 【相關教學推薦:《angular教學》】
依賴注入簡稱DI,是物件導向程式設計中的設計原則,用來減少程式碼之間的耦合度。
我們先來看一段程式碼
class Video{ constructor(url){} } class Note{ video: Video constructor(){ this.video = new Video("https://aaaaa.mp4") } getScreenshot(){ this.video.getScreenshot() } } const note = new Note() note.getScreenshot()
假設我們用一個視訊類,它其中有一個方法getScreenshot 取得截圖,在實例化視訊類別的時候,需要傳入一個視訊url 這樣的參數。現在有一個筆記類,它需要去呼叫視訊類別下的截圖方法,那麼我們就可以說,筆記類是依賴視訊類的。所以在筆記類的內部,我們就需要去實例化視訊類,這樣才能在筆記類中取得視訊類的實例對象,並且呼叫它裡面的截圖方法。
上面程式碼的耦合度過高,不建議使用,比方說如果Video的視訊位址換了一個,那麼在Note中就需要去改變傳入的視訊url,這樣假設要是有更多的類別依賴視訊類,那麼一旦做出更改,那麼所有地方都要跟著改變,非常的不方便。
接下來利用依賴注入解決上面的問題:
class Note{ video: Video constructor(video: Video){ this.video = Video; } } const video = new Video("https://aaaaa.mp4") const note = new Note(video)
我們在類別的外部去實例化視訊類,並且透過參數傳遞的方式把實例傳遞給了筆記類,透過這樣的方式就能夠成功解決耦合度過高的問題,我們把透過參數傳遞實例的這種方式稱為:注入。
優點
透過依賴注入降低了程式碼之間的耦合度,增加了程式碼的可維護性。視訊類別中的程式碼變更也不會去影響到筆記類別了。
在上述實現的過程當中,還是有著一個不是特別理想的地方,就是我們需要在類的外部去實例化視頻類,雖然只有這一處,但是我們還是希望視訊類別的內部再怎麼更改,都不會影響外部程式碼。
在Angular 提供的DI 框架中,我們就不需要自己去做視訊類別的實例化操作,它將實現依賴注入的過程隱藏了,對於開發者來說,只需要使用很簡單的程式碼就可以使用複雜的依賴注入功能。
在Angular 的DI 有四個核心的概念:
#Dependency:元件要依賴的實例對象,服務實例物件
Token:取得服務實例物件的標識,在Angular會維護很多的實例對象,在我們需要取得的時候,就需要透過標識去取得
Injector:注入器,負責建立維護服務類別的實例對象,並在元件中註入服務實例對象,透過參數的方式傳遞給各個元件
Procider:對象,用於配置注入器,指定建立服務實例物件的服務類別和取得實例物件的識別
我們先透過Angular提供的基本語法來建立一個注入器
1、建立注入器
import { ReflectiveInjector } from "@angular/core" //服务类 class Video{} //创建注入器并传入服务类 const injector = ReflectiveInjector.resolveAndCreate([ Video ])
引入ReflectiveInjector其中resolveAndCreate方法用於建立注入器,它接收一個數組,數組中就是需要建立實例物件的類,這個方法會傳回一個注入器 2. 取得注入器中的服務類別實例物件
const video = injector.get(Video)
在injector下有一個get方法,用於傳入標識並且取得實例對象,預設標識就是服務類別的名稱也就是Video
這樣我們就能夠取得到Video的實例對象了,Angular給我們提供的這套DI框架使得我們不需要去手動的實例化某一個類別來獲得它的實例對象,它會來幫我們完成。
2、服務的實例對象為單例模式,注入器在創建服務實例後悔對其進行緩存
const video1 = injector.get(Video) const video2 = injector.get(Video) console.log(video1 === video1)//true
也就是說,無論通過框架獲取多少次實例對象,他返回的都是同一個實例物件
3、但是我們可以透過建立多個注入器,不同的注入器傳回的同一個服務實例化的物件不是同一個
const injector1 = ReflectiveInjector.resolveAndCreate([ Video ]) const injector2 = ReflectiveInjector.resolveAndCreate([ Video ]) const video1 = injector1.get(Video) const video2 = injector2.get(Video) console.log(video1 === video1)//false
4、注入器上面存在一個創建子級注入器的方法為resolveAndCreateChild,這個方法會創建一個子級注入器,父級注入器和子級注入器之間的關係類似於js的作用域鏈,當前註入器查找不到就會去父級注入器查找,例如:
const injector = ReflectiveInjector.resolveAndCreate([ Video ]) const injectorChild = injector.resolveAndCreateChild([]) const video1 = injector.get(Video) const video2 = injectorChild.get(Video) console.log(video1 === video1)//true
像上面这段代码,我们在创建子级注入器的时候,不传递参数,但是在子级注入器实例化的时候,由于自身不存在 Video 这个服务,它就会去父级查找,当然,就找到了父级的 Video 这个服务并且实例化,所以后面的两个实例化对象相等
本文介绍了依赖注入解决的问题和它原生的写法是什么用的,并且介绍了Angular提供给我们的DI框架,用它提供给我们的简单api实现了实例化的过程,并且讲解了注入器,也是会分层级的,能提供给我们更好地一个项目设计方式。之后有机会再来讲解一下provider以及更多的扩展。
更多编程相关知识,请访问:编程视频!!
以上是手把手帶你了解Angular中的依賴注入的詳細內容。更多資訊請關注PHP中文網其他相關文章!