Kotlin 依賴注入實戰指南:解耦程式碼與靈活替換實作

2 min read

什麼是依賴?
廣義:「程式碼直接相依於某個具體實作」
class ChefService { // 依賴具體類別 private val marketA = MarketA() // 依賴具體函數/方法 fun makeSweet() { FileUtils.readFile("recipe.txt") } // 依賴具體實作細節 fun getIngredients() { // 依賴特定URL val url = "<https://marketA.com/api>" } }
在依賴注入情境來說依賴:「一個類別直接創建/使用另一個類別」
class ChefService { // 直接創建實例 = 依賴 private val marketA = MarketA() fun makeSweet() { // 直接使用實例 = 依賴 val ingredients = marketA.buy() // 使用 MarketA 實例的 buy() 方法 } }
直接依賴的問題
測試困難
單元測試需要真實的資料庫/網路環境
無法替換成測試用的模擬物件
靈活性差
- 例:從 Firebase API 改成 Backend API,想換實作方式,需要修改相關程式碼
維護性差
- 實作細節改變,需要修改所有相依的程式碼
依賴小結:
依賴 = 直接相依某個具體實作
依賴注入的依賴 = 在類別中 另個類別直接創建/使用另一個類別
造成程式碼難以測試、替換和維護
需要一個更好的方式來管理這些依賴關係...
改善方法:依賴反轉與注入
依賴反轉是設計原則,而依賴注入是實現此原則的方式之一
概念說明
- 依賴反轉就是將原本依賴某個實作改成依賴抽象,通過介面解耦
依賴反轉原則(DIP)是 SOLID 的一環:
高層模組不依賴低層模組,兩者皆應依賴抽象。
抽象不該依賴細節,細節應依賴抽象。
都是中文但是我看不懂的話,可以參考此篇:
依賴反轉的實現之一:依賴注入
什麼是依賴注入
依賴注入是實現依賴反轉的方法之一,透過「由外部提供依賴」
- 也就是將實作決定權,從類別內部移到外部來決定
注入的方式之一 Constructor Injection(建構子注入)
為什麼要用依賴注入:解耦,方便替換實作
直接依賴問題 | 依賴注入解法 |
private val marketA = MarketA() | class ChefService(private val market: Market) |
難以替換實作 | 透過介面抽象,由外部注入實作 |
怎麼做依賴注入
情境說明
在開發初期常見需要的假資料為例。 測試模式時,使用的資料來源為假資料,非測試模式時則需實際API後端為真實資料來源
Hilt 實作示範
依賴注入本質是一種設計模式,不依賴框架,Hilt 是框架來達到依賴注入的解法之一。
使用 Hilt 模組來決定要注入哪個實作
@Module @InstallIn(SingletonComponent::class) class RepositoryModule { @Provides @Singleton fun provideNoteRepository( appConfiguration: AppConfiguration, dataSourceImpl: RemoteNoteDataSourceImpl, ): NoteRepository { return if (appConfiguration.isTestMode == false) { FakeNoteRepositoryImpl() // <--實作的創建 } else { NoteRepositoryImpl(dataSourceImpl) } } }
使用之處只需要依賴介面
@HiltViewModel class NoteListViewModel @Inject constructor( private val repository: NoteRepository // <--外部注入,由外部決定哪個為實作 ) : ViewModel() { fun getNotes() { noteRepository.getNotes() // 不需要知道具體是哪個實作 } }
總結
依賴反轉:通過介面解耦
依賴注入:可以通過 Hilt 框架來管理具體實作的創建和注入
0
Subscribe to my newsletter
Read articles from Sharon Mai directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Sharon Mai
Sharon Mai
Hi, I'm Sharon