【LT】いらすとやで理解するDI/Dagger/Hilt

LTのYouTube動画 (クリックで再生, 日本語/英語字幕あり)
[<img width=480 src="http://img.youtube.com/vi/qtDXf0H7u1c/hqdefault.jpg">](https://www.youtube.com/watch?v=qtDXf0H7u1c)

※以下は動画の内容を書き起こして一部編集したものです。

# はじめに

先日6月に行われたAndroid 11の発表会で個人的に気になるところがありました。
googleがDI(特にDagger)を推進していくということです。
Android Studio4.1では「Dependency Injection Tools」が組み込まれるということで非常に楽しみです。

一方でDaggerの理解や解説は難しいと思います。
"Dependency Injection" (日本語で"依存性注入")からはじまり、
いろいろなアノテーションの役割を覚える必要があります。
また、最近Daggerを基盤としたHiltというDIライブラリも登場しました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/0183b921-0082-b368-2222-5651a7bb9207.png" width=480 />

そこで、"DIのない生活"、"DIのある生活"、"Daggerのある生活"、"Hiltのある生活"
を分かりやすくいらすとやで解説していきます。

# サンプルケース
「会社」で「仕事」をするのに「イス」が必要というケースを考えます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/6fa34784-f147-1b0a-ff88-6cc675574b4a.png" width=480 /><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/f690d3e2-3665-3004-fd83-fb0d04b17852.png" width=480 />
この場合「会社」が「イス」に依存しているケースと言われます。

# DIのない生活

```kotlin
class Office {
  private var chair = Chair()  // 1

  fun work() {
    print("${chair.name}で仕事") // 2
  }
}
```

"DIのない生活"は上記のコードのような状態です。
オフィスの中で「イス」を作って(1)、
作った「イス」を「仕事」で使うことになります(2)。
この状態は以下2つの問題点があります。

- イスが差し替え不可能という点
- オフィスにイス作成の責任があるという点

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/dce7e5a0-a5b6-67cb-1120-23e2214122da.png" width=640 />

【補足】
コードで見たときに「オフィス」のテストコードを書きたい場合、
イスに不特定な要素(日付で出力が変わる・ランダムで出力が変わる)があるとオフィスのテストコードがかけない状態になります。
また、イスの変更をした場合にオフィスのテストが落ちるケースも考えられます。

そこで「DIのある生活」に切り替えます。

# DIのある生活
今回の依存性は「イス」になるので「イス」を持ち込んで仕事をすると、2つの問題は解決します。
今回のケースでは、「イスを持ち込んだ状態」が「依存性を注入した状態」になります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/6a658a46-8b3d-907a-38f8-95d8fc43d7c8.png" width=640 />

持ち込む方法は"Constructor Injection"、"Field Injection"などがあります。
(詳細は動画で紹介しています)

DIのある生活で依存性の問題は解決しましたが毎回イスの持ち込みを行うのは面倒です。
そこで「Daggerのある生活」に移行します。

# Daggerのある生活
通販とDaggerは共通点が多いです。
Daggerでは`@Inject`, `@Component`, `@Module`, `@Provides`が登場します。以下のような役割です。

|アノテーション|イメージ|目的|
|:--|:--|:--|
|`@Inject`|宅配ボックス|注文を伝える。お届け先。|
|`@Component`|配達員|お届け元からお届け先に商品を配達|
|`@Module`|商店・工場|注文から商品を提供する。お届け元。|

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/289f9835-b733-b697-41a5-b13700458bd2.png" width=640 />

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/242c196d-04dd-b535-938a-e1bb096abf1b.png" width=480 />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/ec6cba64-d9f2-ee1f-df34-34ec61c0462d.png" width=480 />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/1f736ac0-7bd0-1422-f43d-c8acf6b5cc70.png" width=480 />

Daggerは使用時にComponentを呼び出す必要があります。

```Kotlin
component = DaggerYamatoComponent.create()
component.inject(office)
```

「イス」を差し替えるには以下のようにModuleを差し替えることで実現可能です。

```Kotlin
component = DaggerYamatoComponent.builder()
  .yodobashiModule(YodobashiOnlineModule())
  .build()
```

【補足】
[Dagger公式ドキュメント](https://dagger.dev/dev-guide/testing)によると上記Moduleを差し替える方法ではマルチバインディング時等に問題が発生するためComponentを差し替えるほうが良い方法です。

```Kotlin
// DaggerYamatoTestComponentはDaggerYamatoComponentを継承して別途作成する前提
component = DaggerYamatoTestComponent.builder().build()
```

# Hiltのある生活
HiltはDaggerをAndroidに最適化されたDIライブラリという認識です。
「Hiltのある生活」は以下のようになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/0fd5460a-4923-aa23-5233-b9f9ddceca5d.png" width=640 />

大きな変更点として、ComponentはHiltで提供させるので自前で定義する必要がなくなりました。
その代わりにModule側が `@InstallIn` でComponentを指定します。
届け先は「EntryPoint」という概念になり、`@Inject` があるActivityなどには `@AndroidEntryPoint` をつける必要があります。
Hiltを使用する場合はApplicationに `@HiltAndroidApp` を付ける必要があります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/9a41aced-fd87-f772-b3a0-70f0b016d14e.png" width=480 /> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/d5661a16-c9b2-cd13-6c10-513ceec56d7f.png" width=480 />

# おわり
ものすごくざっくりですが、DI, Dagger, Hiltを解説してみました。
画像を並べてみると、「なんでDIやDaggerが良いのか」がなんとなくわかると思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/dce7e5a0-a5b6-67cb-1120-23e2214122da.png" width=240 /><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/6a658a46-8b3d-907a-38f8-95d8fc43d7c8.png" width=240 /><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/289f9835-b733-b697-41a5-b13700458bd2.png" width=240 /><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/0fd5460a-4923-aa23-5233-b9f9ddceca5d.png" width=240 />

以下参考に公式ページ、Mediumのページ、Codelabを貼ります。
MediumのページにはHiltのチートシートがありますのでダウンロードしてつかうと便利です。
CodelabにはHiltのサンプルコードがあるので、自分で編集すると理解が深まります。

# 参考
Dependency injection with Hilt
https://developer.android.com/training/dependency-injection/hilt-android

Dependency Injection on Android with Hilt
https://medium.com/androiddevelopers/dependency-injection-on-android-with-hilt-67b6031e62d

Using Hilt in your Android app
https://codelabs.developers.google.com/codelabs/android-hilt/#0