保羅的學習筆記

Day 22 - 使用依賴注入元件

昨天我們談到使用 Repository 隔離使用端與實作端的直接相依,讓修改實作時變得容易一些。但是如果大家仔細想想可能會發現,假設今天我們有許多地方都使用了 NewsRepositroy,而每個地方都自己指定 NewsRepository 的實作。當今天我們真的想抽換實作時,雖然只要修改建構子的實作指定就好,還是不免要到每個使用到的地方去修改,今天我們就來聊聊如何解決這個問題。

Article image

依賴注入

為了解決這個問題,我們可以引入依賴注入的技術,讓 NewsCubit 不再是自己建立 NewsRepositroy 的實作,而是跟依賴注入容器索取。以上面的例子來說,我們可以在 App 最外層包一個 RepositoryProvider,並在這邊決定 NewsRepository 的實作。

Article image

當建立 NewsCubit 時,則透過 context.read 取得 NewsRepository,由建構子注入 NewsCubit,NewsCubit 再也不需要負責建立 NewsRepository 了。

Article image

這也是依賴注入的功能之一:控制物件的生命週期,將管理物件生命週期的職責,從每個物件中轉移到依賴注入框架中。

抽換實作

當我們使用依賴注入框架,我們是在設定的地方決定實作。當我們決定把 NewsRepository 換成 SqliteDataSource 時,所有使用依賴注入取得 NewsRepository 的地方,都會轉而使用 SqliteDataSource,省去修改每一個類別。

Article image

使用依賴注入框架,當我們更換實作時,我們就不需要逐一到每個使用到的地方更換實作。

其他依賴注入的方式

由於 Flutter 框架本身並沒有提供依賴注入的功能,而在上面的例子中,我們使用 Bloc 提供的 RepositoryProvider 幫助我們在 Flutter 中把相依注入到 News。但是並非所有專案都選擇 Bloc 或 Provider 來做狀態管理。所幸我們還是能從 Flutter 眾多套中之尋找適合的依賴注入套件來搭配使用,我們就用 get_it + injectable 來改造一下範例吧。

首先我們還是得先把套件加入專案中

bash
flutter pub add get_it
flutter pub add injectable
flutter pub add --dev injectable_generator
flutter pub add --dev build_runner

然後我們就能在 Repository 的實作中,設定依賴注入的規則

Article image

最後當我們建立 NewsCubit 時,就能從 getIt 中取得相對應的實作。

Article image

不知道有沒有讀者會好奇,既然 Flutter 沒有反射,那又是如何從依賴注入中取得相對應的實作的呢?其實秘密是利用 build runner 幫我們產生依賴設定的程式碼,像是下圖那樣。

Article image

Provider V.S. GetIt

最後我們來思考一下,當我們想使用依賴注入時,該使用 Provider 或者是 GetIt 呢?在討論之前,我們先來看看兩者的使用方法。這兩種使用方式都有一個共通點,那就是都是 Service Locator 的方式取得相依,也就是無可避免的,我們的程式碼一定會相依於依賴注入框架。

dart
// Provider
context.read<NewsRepositroy>();

// GetIt
getIt<NewsRepository>()

再來讓我們看看不同之處,當使用 Provider 取得相依時,必須有 context 才可以呼叫,原因是 Provider 尋找相依的方式是基於 Widget 樹,也就是說,只有在 View 層的程式碼,我們才能使用 context.read 來尋找相依。當今天使用的地方不在 View 時,我們就無法取得 context,也就無法取得相依,使用的地方會相對於 GetIt 更為受限。

結論

使用依賴注入,將物件建立與管理的職責可以轉移到依賴注入框架中,讓我們的程式碼可以專注如何與依賴注入框架互動即可。當我們想抽換實作,也可以直接修改依賴注入設定即可,而不必修改使用端程式碼。

— 全文完 —

如果這篇對你有幫助,可以分享給朋友,或追蹤後續更新。我在 Threads 也會貼一些零碎想法。