前端理解依賴注入(控制反轉)

2020-12-16 51CTO

前端的技術的極速發展,對前端同學來說也是一個不小的挑戰,有各種各樣的東西需要學,在開發過程中經常會被後端同學嘲諷,對於前端來講根本就不存在類的概念,很多時候需要把大量的業務代碼堆積在頁面或者組件中,使組件和頁面變得特別的臃腫,一旦業務邏輯複雜的情況下,及時組件化做的很好,仍然避免不了難以維護。

之所以會被後端同學嘲諷,一基礎掌握不紮實,對前端理解不到位,二缺乏面向對象思想,三對業務與基礎傻傻分不清楚。ECMAScript 2015與Type Script的推出,提出了一個很重要的概念就是class(類)的概念。在沒有class之前為了前端能夠有類的概念,一直都是使用構造函數模擬類的概念,通過原型完成繼承。

雖然前端提出了很多概念(模塊化,組件化...),個人覺得面向對象的應用是前端對於項目以及整體架構來講是一件利器,代碼結構好與壞與面向對象有一定的關係,但不是全部。不過我們可以藉助計算機領域的一些優秀的編程理念來一定程度上解決這些問題,接下來簡單的說下依賴注入(控制反轉)。

什麼是依賴注入

依賴注入一般指控制反轉,是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。其中最常見的方式叫做依賴注入,還有一種方式叫依賴查找。通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。

從上面的描述中可以發現,依賴注入發生在2個或兩個以上類,比如現在有兩個類A與B類,如果A是基礎類存在的話,B做為業務類存在,B則會依賴於A,上面有一句話很重要由一個調控系統內所有對象的外界實體將其所依賴的對象的引用傳遞給它,個人理解,在B類中使用A類的實例,而不是繼承A類。

對面向對象了解的同學應該了解,面向對象7大原則:

  1. 單一職責
  2. 開閉原則
  3. 裡氏替換
  4. 依賴倒置
  5. 接口隔離
  6. 迪米特法則
  7. 組合聚合復用原則

詳細解釋參照:面向對象之七大基本原則(javaScript)

然而使用依賴注入的事為了降低代碼的耦合程度,提高代碼的可拓展性。以上都是一些面向對象的思想,我們參考一下以上最重要的幾個原則,層模塊不應該依賴低層模塊。兩個都應該依賴抽象,抽象不應該依賴具體實現,具體實現應該依賴抽象。

  1. // 球隊信息不依賴具體實現 
  2. // 面向接口即面向抽象編程 
  3. class Fruit { 
  4.     constructor(name) { 
  5.         this.name = name 
  6.     } 
  7. class Tropical { 
  8.     // 此處的參數,是teamInfo的一個實例,不直接依賴具體的實例 
  9.     // 面向抽象 
  10.     constructor(fruit) { 
  11.         this.fruit = fruit; 
  12.     } 
  13.     info() { 
  14.         console.log(this.fruit.name
  15.     } 
  16. // 將依賴關係放到此處來管理,控制權也放到此處 
  17. // Tropical和Fruit之間不再有直接依賴 
  18. // 原本直接掌握Fruit控制權的Tropical不再直接依賴 
  19. // 將依賴控制,落在此處(第三方模塊專門管理)即為控制反轉 
  20. var ym = new Tropical(new Fruit('香蕉')) 
  21. ym.info() 
  22. var kobe = new Tropical(new Fruit('菠蘿')) 
  23. kobe.info() 

依賴注入的作用

初始化被依賴的模塊

如果不通過依賴注入模式來初始化被依賴的模塊,那麼就要依賴模塊自己去初始化了

那麼問題來了:依賴模塊就耦合了被依賴模塊的初始化信息了

注入到依賴模塊中

被依賴模塊已經被其他管理器初始化了,那麼依賴模塊要怎麼獲取這個模塊呢?

有兩種方式:

沒用依賴注入模式的話是1,用了之後就是2

想想,你需要某個東西的時候,你去找別人要,你需要提供別人什麼信息?最簡單的就是那個東西叫什麼,即你需要提供一個名稱。所以,方式1的問題是:依賴模塊耦合了被依賴模塊的名稱還有那個別人而方式2解決了這個問題,讓依賴模塊只依賴需要的模塊的接口。

依賴注入的優點

依賴注入降低了依賴和被依賴類型間的耦合,在修改被依賴的類型實現時,不需要修改依賴類型的實現,同時,對於依賴類型的測試。依賴注入方式,可以將代碼耦合性降到最低,而且各個模塊拓展不會互相影響,

  1. 實現數據訪問層,也就是前端你的數據請求層
  2. 模塊與接口重構,依賴注入背後的一個核心思想是單一功能原則,這意味著這些對象在系統的任何地方都可以重用。
  3. 隨時增加單元測試,把功能封裝到整個對象裡面會導致自動測試困難或者不可能。將模塊和接口與特定對象隔離,以這種方式重構可以執行更先進的單元測試。

Vue中使用

上面寫的例子也只是對依賴注入見單的使用,在項目過程中往往就不是這麼簡單了,肯定不會向例子這麼簡單,而是很複雜很龐大的一個項目。項目中分為各種各樣的模塊,這種情況又改如何處理?在JavaScript中常見的就是依賴注入。從名字上理解,所謂依賴注入,即組件之間的依賴關係由容器在運行期決定,形象的來說,即由容器動態的將某種依賴關係注入到組件之中。

前端項目中並不像後端一樣,各種各樣的類,雖然前端可以寫class,若是React項目的話,還會好很多,由於其框架使用,全部是基於class但是在vue項目中,又應該怎麼具體體現呢?頁面中的業務也是可以作為類存在最終注入到Vue頁面中,最終完成業務邏輯。

通過依賴注入到底想要達到到什麼效果呢,依賴注入最終想要達成的效果則是,頁面的表現與業務相脫離,從本質上來說,頁面的展現形式與業務邏輯其實沒有根本聯繫的。若使用這種依賴注入的形式,則可以輕鬆的把業務和頁面表現分離開,頁面更加的專注於展示,而所注入的東西則更加的專注於業務的處理。項目也則會變得容易維護。

index.vue

  1. <template> 
  2.   <div> 
  3.     <el-button @click="getList" 
  4.               :loadding="loadding">獲取表格數據</el-button> 
  5.     <ul> 
  6.       <li v-for="(item,index) of list" 
  7.           :key="index">{{item}}</li> 
  8.     </ul> 
  9.   </div> 
  10. </template> 
  11. <script> 
  12. import operation from "@/business/index/Operation.js"
  13. export default { 
  14.   data() { 
  15.     return { 
  16.       list: [], 
  17.       query:{}, 
  18.       loadding:false 
  19.     } 
  20.   }, 
  21.   methods:{ 
  22.     async getList(){ 
  23.       let {query} = this; 
  24.       this.loadding = true
  25.       try{ 
  26.         this.list = await operation.getData.call(this,query); 
  27.       }catch(error){ 
  28.         console.log(error) 
  29.       } 
  30.       this.loadding =false
  31.     } 
  32.   } 
  33. </script> 
  34. <style> 
  35. @import "@/style/index.vue"
  36. </style> 

operations.js

  1. import request from "@/api/errorList/index.js"
  2. class Operation { 
  3.     async getData(query){ 
  4.         //  this 指向Vue實例 
  5.         try { 
  6.             let res = await request.getErrorList(query); 
  7.             let {list} = res; 
  8.             //  這裡可以對數據進行二次處理 
  9.             //  寫一些其他業務 
  10.             Promise.resolve(list); 
  11.         }catch(error){ 
  12.             Promise.reject(error); 
  13.         } 
  14.     } 
  15. }; 
  16. export default new Operation(); 

上面也是在項目中的一個簡單的應用,使頁面表現數據請求與數據處理,業務相脫離,讓項目變得更加容易維護。

控制反轉這裡控制權從使用者本身轉移到第三方容器上,而非是轉移到被調用者上,這裡需要明確不要疑惑。控制反轉是一種思想,依賴注入是一種設計模式。

依賴注入最終想要達到的目的,首先得為模塊依賴提供抽象的接口,下來應該能夠註冊依賴關係

在註冊這個依賴關係後有地方存儲它,存儲後,我們應該把被依賴的模塊注入依賴模塊中,注入應該保持被傳遞函數的作用域,被傳遞的函數應該能夠接受自定義參數,而不僅僅是依賴描述。

總結

在JavaScript中依賴注入的概念不像Java中被經常提到,主要原因是在js中很容易就實現了這種動態依賴。其實我們大部分人都用過依賴注入,只是我們沒有意識到。即使你不知道這個術語,你可能在你的代碼裡用到它百萬次了。希望這篇文章能加深你對它的了解。

需要注意的是,依賴注入只是控制反轉的一種實現方式,正確的依賴管理是每個開發周期中的關鍵過程。JavaScript 生態提供了不同的工具,作為開發者的我們應該挑選最適合自己的工具。

相關焦點

  • 控制反轉(IoC)與依賴注入(DI)詳解
    我們帶著下面的5個問題來學習本博客什麼是控制反轉(IoC)控制反轉(IoC)有什麼作用控制反轉(IoC)是怎麼分類的什麼是依賴注入(DI)Spring的IoC容器是怎麼進行依賴注入的什麼是控制反轉(IoC)控制反轉即IoC (Inversion of Control),它把傳統上由程序代碼直接操控的對象的調用權交給容器
  • 淺析控制反轉
    那到底什麼被反轉了?獲得依賴對象的過程被反轉了。控制反轉 (下文統一簡稱為 IoC) 把傳統模式中需要自己通過 new 實例化構造函數,或者通過工廠模式實例化的任務交給容器。通俗的來理解,就是本來當需要某個類(構造函數)的某個方法時,自己需要主動實例化變為被動,不需要再考慮如何實例化其他依賴的類,只需要依賴注入 (Dependency Injection, 下文統一簡稱為 DI), DI 是 IoC 的一種實現方式。所謂依賴注入就是由 IoC 容器在運行期間,動態地將某種依賴關係注入到對象之中。
  • 使用 Autofac 進行依賴注入
    為了解耦前面的人提出各種理論,主要思想是控制反轉,而現在主流的主要是兩個:依賴注入、服務定位(有篇英文文章特意討論這種模式,最終的結論是否定的,乍看了一眼,沒看懂)    有了某個思想便可以在程序中體現,用多了,人們就去對它進行封裝,普通的人封裝的大概就自己用,高人封裝了便成了組件。現在基本上都在弄 .net ,所以說的技術也基本上是這一塊的。.
  • 軟體設計原則之依賴反轉(Dependency inversion principle,DIP)
    比如依賴注入、MVC,從而開發出高內聚低耦合的應用代碼。這是如何做到的?2 定義DIP是指一種特定的解耦(傳統的依賴關係創建在高層次,而具體的策略設置則應用在低層模塊)形式,使得高層模塊不依賴於低層模塊的實現細節,依賴關係被反轉,從而使得低層模塊依賴於高層模塊的需求抽象。
  • 【Spring框架】之IoC控制反轉
    官網:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-introduction 章節一 什麼是控制反轉IoC?
  • Dagger2讓你愛不釋手-基礎依賴注入框架篇
    Scope怎麼起到作用域控制?…..各種疑問就橫空而出。所以也許會有正在學習或即將要使用dagger2的同學在使用過程中遇到和我一樣的困惑,因此我決定把我對dagger2的理解、使用經驗分享給大家,希望能對大家有幫助。我會分幾節給講解dagger2。本節內容Inject,Component,Module,Provides它們是什麼?
  • Java Web系列:Spring依賴注入基礎
    因此學習Spring Framework在架構和模式方面的結構和原理,對我們在架構和模塊級別的理解幫助極大。Spring Framework(參考1)的宗旨是簡化Java開發,主要的手段如下:(1)在架構上解耦:通過DI(依賴注入)管理類型依賴,通過AOP分離關注點,減少重複代碼。
  • dotNET Core 3.X 依賴注入
    如果說在之前的 dotNET 版本中,依賴注入還是個比較新鮮的東西,那麼在 dotNET Core 中已經是隨處可見了,可以說整個 dotNET Core 的框架是構建在依賴注入框架之上。本文說說對 dotNET Core 中依賴注入的理解。
  • Java Spring中依賴注入與工廠設計模式的區別?- 知識鋪
    2.5 依賴注入:客戶端類沒有關於如何創建和管理其依賴關係的線索。它只知道依賴關係。三、Spring Framework3.1 bean類的框架注入的,沒有任何硬編碼依賴項,是由IOC容器注入與管理。Spring IOC只是依賴注入模式的實現。
  • 【19】ASP.NET Core 依賴注入
    ASP.NET Core 依賴注入在這個視頻中,我們將通過一個例子詳細討論依賴注入。
  • Android 依賴注入框架 Dagger 2.1 詳解
    本文適合人群:從未了解過dagger僅簡單使用API但不了解為何這樣使用可以很好的使用並理解dagger,僅需了解新版本(可以直接跳到第四部分)Dependency Injection(DI)翻譯成中文也就是依賴注入,我們先用一個很簡單的例子來了解一下    class Clothes {
  • 會接正反轉電路,也會接異地控制電路,正反轉異地控制呢?
    朋友們大家好我是大俵哥,今天有個朋友微我--問我正反轉電路怎麼實現異地控制。電機我就問他,正反轉控制電路和自鎖異地控制都會嗎?他回答,單獨分開會接,但是組合在一起的不會接。從這個問題就可以看出,個別的朋友對電氣控制原理還不是太熟練,不懂得靈活運用,今天俵哥就把正反轉異地控分享一下。
  • 代碼要依賴倒轉,還要接口隔離,這些原則裡再要依賴注入不是吧?
    目錄 依賴倒轉原則: 依賴注入 構造注入: 設值注入: 接口隔離原則:
  • 你好,談談你對前端路由的理解
    前言好了不裝了,今天我就化身性感面試官在線問大家一個問題,「談談你對前端路由的理解」。看到這個問題,那回答可多了去了。但是換位思考一下,你問候選人這個問題的時候,你想要得到什麼答案?以我個人拙見,我希望候選人能從全局解讀這個問題,大致以下三點。
  • Anrdoi依賴注入框架koin
    Koin 是什麼Koin 是為 Kotlin 開發者提供的一個實用型輕量級依賴注入框架,採用純 Kotlin 語言編寫而成,僅使用功能解析,無代理、無代碼生成、無反射。官網地址優勢依賴注入好處增加開發效率、省去重複的簡單體力勞動 首先new一個實例的過程是一個重複的簡單體力勞動,依賴注入可以把new一個實例的工作做了,因此我們把主要精力集中在關鍵業務上、同時也能增加開發效率上。
  • 詳解PLC控制電動機正反轉電路
    PLC控制電動機正反轉電路(一)圖3-1(a)為一種PLC控制電動機正反轉電路接線圖,圖3-1(b)、(c)所示為該電路的梯形圖及指令語句表,其輸入/輸出地址分配如表3-1所示。圖3-1 PLC 控制電動機正反轉電路(續表3-1 圖3-1(a)所示電路的PLC輸入/輸出地址分配表PLC控制電動機正反轉電路由主電路和控制電路兩大部分組成
  • Web前端三大主流框架是什麼?
    前端框架對於前端開發的好處是顯而易見的,比如減少代碼中因失誤產生的bug,還能大大節約時間和人力成本,縮短開發周期等等。目前,市面上Web前端三大主流框架分別指的是Angular、React和Vue,在Web前端開發中,它們平分秋色,各有優劣。
  • 前端如何正確使用中間件?
    阿里妹導讀:中間件可以算是一種前端中常用的」設計模式「了,有的時候甚至可以說,整個應用的架構都是使用中間件為基礎搭建的。那麼中間件有哪些利弊?什麼才是中間件正確的使用姿勢?本文將分享作者在實際使用中的一些想法,歡迎同學們共同討論。文末福利:下載《大促背後的前端核心業務實踐》電子書。
  • 三菱案例|如何使用正反轉控制電路轉換成PLC控制!
    【動作描述】(1)現有聯鎖正反轉控制電路一份,如下圖,SB1是停止按鈕,SB2是正轉按鈕,SB3是反轉按鈕,FR是熱過載保護我們嘗試把它改造成PLC控制的電路。#三菱PLC入門#【設備硬體】(1)三菱PLC :FX1S-10MR-ES-UL因為功能比較簡單,我們選擇PLC可以選擇最低配置的型號,繼電器輸出的可以直接控制交流接觸器