什么是依賴注入?不管是js中的一些前端框架還是,java,C#等中的一些后端語言開發框架中,都會涉及這個的詞語:依賴注入,單純聽這個詞匯好像很厲害的樣子,大部分人都會對未知的事物產生排斥和畏懼,但是其實只要通過簡單學習后你會發現其實並沒有想象中那么復雜。
1,基本概念
依賴注入?控制反轉?
依賴注入是控制反轉的一種具體實現方式,那什么又是控制反轉:它是面向對象編程中的一種設計原則,其作用主要用來減低計算機代碼之間的耦合度,
其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體,將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。
2,概念理解與運用
如果有一定的面向對象思想其實要理解這一概念的並不算太難,我們常規面向對象最基本的思想就是我們會把某些業務模塊需要封裝成為一個類,然后在需要的地方去實例化調用,我們不妨舉一個生活中的簡單栗子,把它體現到代碼之中后,看看代碼不使用依賴注入和使用依賴注入有什么區別:
如果把我自己比作一個類,假定我這個類里面有工作“Work()”和休息放假“Holiday()”兩個函數,然后我在工作和休息兩個函數中都會用到我的蘋果手機,工作“Work()”函數中會用手機打電話和發郵件,休息“Holiday()”函數會用手機玩游戲、上網還有看視頻,我們把手機也看成另一個類,手機類分別實現了:打電話:Call()、發郵件:Eamil()、玩游戲:PlayGame()、上網:Internet()、看視頻:VideoPlay()五個函數。代碼如下:
public class Person { } public class Me : Person { public void Work() { //…… 省略若干代碼 iphone phone = new iphone(); phone.Call(); phone.Eamil(); } public void Holiday() { //…… 省略若干代碼 iphone phone = new iphone(); phone.PlayGame(); phone.VideoPlay(); phone.Internet(); } } public class iphone { public void Call() { //…… 省略若干代碼 Console.WriteLine($"iphone手機打電話"); } public void Eamil() { //…… 省略若干代碼 Console.WriteLine($"iphone手機發送郵件"); } public void PlayGame() { //…… 省略若干代碼 Console.WriteLine($"iphone手機玩游戲"); } public void VideoPlay() { //…… 省略若干代碼 Console.WriteLine($"iphone手機播放視頻"); } public void Internet() { //…… 省略若干代碼 Console.WriteLine($"iphone手機上網"); } }
調用代碼:
public class Program { public static void Main(string[] args) { int[] Holiday = { 0, 6 }; //獲取當前時間 DateTime time = DateTime.Now; //實例化Me對象 Me me = new Me(); if (Holiday.Contains((int)time.DayOfWeek)) { //如果當前時間為周六,周日,執行Holiday me.Holiday(); } else { //如果當前時間不為周六,周日,執行Work me.Work(); } } }
看到這個代碼我們覺得很OK,終於可以愉快的工作和休息了,但是好景不長,有一天我從蘋果手機換成了華為手機,為了我代碼可以正常運行,我必須把所有實例化過iphone類的地方改成實例化華為類,在將來我每換一次手機,我的對應的實例也會跟着改變,代碼實例對象的地方存在耦合。所以我們要想辦法解耦,怎么處理呢?
public class Person { } public class Me : Person { private phone myphone; public Me(phone _phone) { myphone = _phone; } public void Work() { //…… 省略若干代碼 myphone.Call(); myphone.Eamil(); } public void Holiday() { //…… 省略若干代碼 myphone.PlayGame(); myphone.VideoPlay(); myphone.Internet(); } } public abstract class phone { public abstract void Call(); public abstract void Eamil(); public abstract void PlayGame(); public abstract void Internet(); public abstract void VideoPlay(); } public class iphone : phone { public override void Call() { //…… 省略若干代碼 Console.WriteLine($"iphone手機打電話"); } public override void Eamil() { //…… 省略若干代碼 Console.WriteLine($"iphone手機發送郵件"); } public override void PlayGame() { //…… 省略若干代碼 Console.WriteLine($"iphone手機玩游戲"); } public override void VideoPlay() { //…… 省略若干代碼 Console.WriteLine($"iphone手機播放視頻"); } public override void Internet() { //…… 省略若干代碼 Console.WriteLine($"iphone手機上網"); } } public class huaweiphone : phone { public override void Call() { //…… 省略若干代碼 Console.WriteLine($"華為手機打電話"); } public override void Eamil() { //…… 省略若干代碼 Console.WriteLine($"華為手機發送郵件"); } public override void PlayGame() { //…… 省略若干代碼 Console.WriteLine($"華為手機玩游戲"); } public override void VideoPlay() { //…… 省略若干代碼 Console.WriteLine($"華為手機播放視頻"); } public override void Internet() { //…… 省略若干代碼 Console.WriteLine($"華為手機上網"); } }
代碼標紅的地方是主要涉及依賴注入的地方,我們把手機類作為一個父類,然后華為和iPhone都繼承此類,然后我們把手機類作為Me類的成員,這樣改動后我們的調用代碼如下
public class Program { public static void Main(string[] args) { int[] Holiday = { 0, 6 }; //獲取當前時間 DateTime time = DateTime.Now; //實例化手機對象 phone phone = new huaweiphone(); //實例化Me對象 Me me = new Me(phone); if (Holiday.Contains((int)time.DayOfWeek)) { //如果當前時間為周六,周日,執行Holiday me.Holiday(); } else { //如果當前時間不為周六,周日,執行Work me.Work(); } } }
代碼這樣更改之后不管我們要用iPhone類還是華為類還是其他新的手機類去實現我們的Holiday()和Work()中的函數,我們不需要對Me類做任何改動,只需要去改變傳輸的對象,在調用時靈活的將我們所需要的依賴對象注入到Me類之中,這就就是傳說中的依賴注入。
回看前面的例子再用我自己的話來理解依賴注入:就是把依賴部分(代碼不可控或者經常變動的耦合的部分)變成一個抽象的成員(類、抽象類或接口),然后根據具體所需要的實例去靈活的注入依賴,來達到控制反轉的效果,從而實現代碼解耦。
上面這個簡單的例子中依賴部分就是iPhone類,華為類這種可能存在變動的類,每種手機具體實現打電話Call(),發郵件Eamil()等功能的方式可能都有差異,我們只能在具體要用到的時候才會知道到底要用哪一種手機,所以在具體調用的時候去注入手機對象是相對靈活而且耦合度低的一種方案。
3,C#常用的依賴注入方式
1,通過構造器進行依賴注入
2,通過屬性的訪問器進行依賴注入
3,通過接口實現依賴注入
4,通過反射,特性也可以實現依賴注入
我們上面例子是通過構造函數實現的簡單的依賴注入,其他幾種方式在搞清楚代碼基礎語法概率之后其實也都差不多,我就不一一舉例了,不管用什么方式實現依賴注入,理解其中的基本思想是最重要的。