Java中的依賴注入

原文:https://droidyue.com/blog/2015/06/13/talk-show-about-dependency-injection/

在面向對象編程中,我們經常處理處理的問題就是解耦,程序的耦合性越低表明這個程序的可讀性以及可維護性越高。控制反轉(Inversion of Control或IoC)就是常用的面向對象編程的設計原則,使用這個原則我們可以降低耦合性。其中依賴注入是控制反轉最常用的實現。

什麼是依賴

依賴是程序中常見的現象,比如類Car中用到了GasEnergy類的實例energy,通常的做法就是在Car類中顯式地創建GasEnergy類的實例,並賦值給energy。如下面的代碼

1
2
3
4
5
6
7
8
9
10
11
interface Energy {
      
}
  
class GasEnergy implements Energy {
      
}
  
class Car {
  Energy energy = new GasEnergy();
}

存在問題

  • 類Car承擔了多餘的責任,負責energy對象的創建,這必然存在了嚴重的耦合性。舉一個現實中的例子,一輛汽車使用哪種能源不是由汽車來決定,而是由汽車製造商(CarMaker)來決定,這是汽車製造商的責任。
  • 可擴展性,假設我們想修改能源爲電動力,那麼我們必然要修改Car這個類,明顯不符合開放閉合原則。
  • 不利於單元測試。

依賴注入

依賴注入是這樣的一種行爲,在類Car中不主動創建GasEnergy的對象,而是通過外部傳入GasEnergy對象形式來設置依賴。 常用的依賴注入有如下三種方式

構造器注入

將需要的依賴作爲構造方法的參數傳遞完成依賴注入。

1
2
3
4
5
6
class Car {
  Energy mEnergy;
  public Car(Energy energy) {
      mEnergy = energy;
  }
}

Setter方法注入

增加setter方法,參數爲需要注入的依賴亦可完成依賴注入。

1
2
3
4
5
6
7
class Car {
  Energy mEnergy;
      
  public void setEnergy(Energy energy) {
      mEnergy  = energy;
  }
}

接口注入

接口注入,聞其名不言而喻,就是爲依賴注入創建一套接口,依賴作爲參數傳入,通過調用統一的接口完成對具體實現的依賴注入。

1
2
3
4
5
6
7
8
9
10
11
interface EnergyConsumerInterface {
  public void setEnergy(Energy energy);
}
  
class Car implements EnergyConsumerInterface {
  Energy mEnergy;
      
  public void setEnergy(Energy energy) {
      mEnergy  = energy;
  }
}

接口注入和setter方法注入類似,不同的是接口注入使用了統一的方法來完成注入,而setter方法注入的方法名稱相對比較隨意。

框架取捨

依賴注入有很多框架,最有名的就是Guice,當然Spring也支持依賴注入。Guice採用的是運行時讀取註解,通過反射的形式生成依賴並進行注入。這種形式不太適合Android移動設備,畢竟這些操作都在運行時處理,對性能要求較高。

Dagger則是Android開發適合的依賴注入庫,其同樣採用類註解的形式,不同的是它是在編譯時生成輔助類,等到在運行時使用生成的輔助類完成依賴注入。

用還是不用

其實注入框架用還是不用,是一個問題,如若使用框架,則要求團隊每一個人都要遵守說明來編寫代碼解決依賴注入。而這些框架其實也並非很容易就能上手,學習係數相對複雜,難以掌握,這也是需要考慮的問題。

個人觀點爲不推薦也不反對使用這些框架,但是覺得有些時候我們寄希望於一個框架,不如平時注意這些問題,人爲避免何嘗不是對自己的一種基本要求呢?

依賴查找

依賴查找和依賴注入一樣屬於控制反轉原則的具體實現,不同於依賴注入的被動接受,依賴查找這是主動請求,在需要的時候通過調用框架提供的方法來獲取對象,獲取時需要提供相關的配置文件路徑、key等信息來確定獲取對象的狀態。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章