【Dagger】全くわからないDependency Injectionを完全に理解するための記事

皆さん、こんにちは。kitakkunと申します。

「**Dependency Injection（依存性注入）**」って知ってますか？
この記事は、このDIを「**完全に理解した**」状態になるのが目標です。

誤解しないで欲しいのですが、「完全に理解した」は文字通り完全に理解することを言っているのではなくて、まずは最初の山場を超えてしまいましょうという話です。

Daggerに関しては色々調べて試行錯誤してこうしたら動いたよくらいの理解なので、一部誤っているかもしれません。識者の方、遠慮なくコメントでご指摘願います。

# 実は皆さん、既にDI経験者です

実はですね。ある程度の期間プログラミングをやっていれば、大抵DIは無意識のうちにやっているはずです。クラスやモジュールを分けながらプログラミングをしていると必然的にDIしたくなってきます。それでは、説明します！

（読んでる途中で、「いや、そんなのやってないよ！」と思った方も、「そうなんだ」くらいに読んでいただけると嬉しいです）

## RPGゲームのキャラクタークラスを例に考えてみる

今皆さんは、RPGゲームを作っています。ゲーム内で戦闘を行うキャラクターはすべて`Character`クラスで定義されているとしましょう。(`open`はkotlinにおいて継承を許可する修飾子です）

```kotlin
open class Character {}
```

`Character`は、防具（`Armer`）と武器（`Weapon`）を装備することができます。これらによって防御力や攻撃力などのパラメータ、そして攻撃モーションなどが決定するとします。

```kotlin
open class Armer {}
open class Weapon {}
```

繰り返しになりますが、`Character`には`Armer`と`Weapon`を装備できます。`Character`が`Armer`と`Weapon`を持っていると考えたら、以下のような設計が考えられます。内部にメンバとして定義してしまう、というものです。

```kotlin
open class Character {
    val armer = Armer()
    val weapon = Weapon()
}
```

ここで、一つ問題が生じます。キャラクターは自由に装備を変更できるとしたら・・？
、、、ああ、わかりますよ。こうすればいいんでしょう？

```kotlin
open class Character {
    var armer = Armer()
    var weapon = Weapon()
}

val character = Character()
character.armer = MukiMukiArmer()
character.weapon = MoriMoriShord()
```

まあ確かに、こうすれば装備変更は可能だけど、、。後から代入するの忘れたときとか、`armer`や`weapon`が直接置き換えられるようになってて危険じゃない？
その上、**キャラクターを作るときに必ず防具と武器が必要**っていうんなら、**作るときに渡してあげる**のが自然じゃないかな。じゃあ、こう？

```kotlin
open class Character (val armer: Armer, val weapon: Weapon) { }
```

いいですね。これなら色んな武器や防具を渡して、様々なキャラクターを作れて便利そうです。

・・・ はい。これが、Dependency Injectionです。・・・ええ？「なるほど、わからん」ですか。次節でもうちょっと詳しく説明します。

## 一体どこがDIなの？

凄く当たり前にやることなので、気付かない方も多いかもしれませんが、DIはとても身近な存在なのです。
先程の例について、詳しく説明します。

> **キャラクターを作るときに必ず防具と武器が必要**っていうんなら、**作るときに渡してあげる**のが自然じゃないかな。

と、わざと太字にしました。これ、難しく言うと次のように表現できます。

> `Character`クラスのインスタンス化に`Armer`と`Weapon`が必要なら、`Character`クラスのコンストラクタに渡してあげるのが自然じゃないかな。

もっと行きましょう。

> `Character`クラスが`Armer`と`Weapon`に **依存している** なら、コンストラクタで **注入してあげる** のが自然じゃないかな。

おや、「**依存している**」という表現が出てきました。また、「**注入してあげる**」という言葉も出てきました。
「**依存**」と「**注入**」・・・？ **依存性注入**・・・？？ これ、**DIやーーーーん！！**

つまり、その**クラスを使うために必要なクラスを、内部で作るのではなく外部から注入**してあげるというのが、**Dependency Injection**です。どうですか？「完全に理解」しましたか？

# DIすると何が嬉しいのか

一般にDIをすると、**テストが簡単になる**と言われています。でも、個人レベルでプログラミングしていると、あまりテストは書かないし、利点を感じにくいかもしれません。

そのため、先程の例のように、内部で生成してしまうと柔軟性が損なわれるんだな、くらいの理解で最初は大丈夫だと思います。DIする前は防具と武器が固定で困ってましたけど、DIしたら色んな防具と武器をキャラクターに装備させられるようになりましたね。

# DIすると何が残念なのか

DIすると、インスタンスの生成がちょっと面倒になります。なぜなら、先程の例で言えば、DIする前は

```kotlin
val character = Character()
```

でキャラクターを作れていたのに、DIした後は

```kotlin
val armer = Armer()
val weapon = Weapon()
val character = Character(armer, weapon)
```

としてインスタンス化しなければなりません。毎回これをやるのは非常に面倒くさいですね。今回の場合は多分渡すものが毎回変わる類のものかもしれませんが、渡すものが決まっている場合とかはなおさら面倒くさいです。

渡すものが決まっている、というのは例えばデータベースへアクセスするための`Database`クラスがあるとして、メッセージ投稿を担うクラス`PostCreator`がこの`Database`クラスに依存しており、DIした場合などです。

```kotlin
class PostCreator (private val database: Database) {}
```

**勝手に突っ込んでくれよ！！** と、思いませんか。はい。実は勝手に突っ込んでくれるツールがあります。皆さんご存知かもしれません。「**Dagger**」です。

# Daggerは難しそうだけど、難しくない

DIを自動化するツールとして、Google社の提供する「Dagger」があります。

このDaggerはよく、難しすぎるだとか言われ敬遠されがちなのですが、やっていること自体はそんなに難しくはありません。ちょっと難しく感じるのは、見慣れないアノテーションをはじめ、コンポーネントやモジュールといった特殊な概念のせいです。

ここでは、Daggerを完全に理解するために丁寧にセットアップ方法を説明していきます！（すみません、daggerの使い方にフォーカスしたいので`build.gradle`周りの設定とかは割愛します）

## `@Inject` による依存性注入箇所の指定 
Daggerにおいて依存性注入を行いたい箇所には`@Inject`アノテーションをつけます。例えば、先程の例ならば

```kotlin
open class Character @Inject constructor(val armer: Armer, val Weapon) {}
```
といった具合になります。ちなみに、constructorに`@Inject`をつけたときの依存性注入のことを**コンストラクタインジェクション**と言います。

一方で、最初に実は内部フィールドに防具や武器を定義するという実装を行っていましたが、コンストラクタで渡す以外にもう一つインスタンス化の後データをはめ込むタイプのインジェクションもあります。

```kotlin
open class Character {
    var armer = Armer()
    var weapon = Weapon()
}

val character = Character()
character.armer = MukiMukiArmer()
character.weapon = MoriMoriShord()
```

これですね。これを`@Inject`を用いてやるならば、フィールドに`@Inject`をつけ、フィールドを`lateinit var`にします。

```kotlin
open class Character {
    @Inject lateinit var armer: Armer
    @Inject lateinit var weapon: Weapon
}
```

この手法は、**フィールドインジェクション**といい、コンストラクタ呼び出しがシステムにより行われ、コンストラクタインジェクションができない場合などに利用されます。

## `@Module` による注入データの定義

前節では`Character`クラスの依存性注入対象を、`@Inject`を用いて行いました。次に、該当の型のインスタンスを自動で供給するためのモジュールを作成します。モジュールとなる`object`または`class`には`@Module`アノテーションをつけます。

```kotlin
@Module
object MyModule {}
```

では、`Armer`と`Weapon`を供給（`@Provides`）するための関数を定義します。

```kotlin
@Module
object MyModule {
    @Provides
    fun provideArmer(): Armer = Armer()
    @Provides
    fun provideWeapon(): Weapon = Weapon()
}
```
これで、`@Inject`アノテーションの付いた`Armer`型、および`Weapon`型の変数には自動でそのインスタンスが注入されます。

> 補足: プログラム中で1つしかインスタンスを持たない、シングルトンのクラスを注入したい場合は`@Provides`に合わせて`@Singleton`アノテーションをつけます。
> ```kotlin
> @Module
> object MyModule {
>     @Provides
>     @Singleton
>     fun provideSomeSingleton(): SomeSingleton = SomeSingleton()
> }
> ```

ここまででとりあえず`Character`クラスのインジェクションは終わりです。しかし、コンストラクタインジェクションの方は正常に動きますが、フィールドインジェクションの方は上手く動いてくれません。フィールドインジェクションを機能させるために必要な、「コンポーネント」について次節では説明したいと思います。

## `@Component` によるフィールドインジェクション

フィールドインジェクションは、モジュールだけでは完結しません。別途コンポーネントを作成し、該当のクラスで明示的にインジェクトしてやる必要があります。ただ、基本的にコンストラクタインジェクションで完結するので、こちらのコンポーネントに関しては使う機会が限られているかと思います。しかし、必要になるかもしれないので一応軽く説明します。

`Character`クラスをフィールドインジェクションで実装したとしましょう。

```kotlin
open class Character {
    @Inject lateinit var armer: Armer
    @Inject lateinit var weapon: Weapon
}
```

これに注入するイメージで進めていきます。

コンポーネントのインタフェースを定義します。（インタフェースを定義すればあとは内部で実装部や自動でやってくれます）
```kotlin
@Component(modules = [MyModule::class])
interface MyComponent {}
```
`@Component`アノテーションは引数にモジュールクラスの配列を受け取ります。今回の場合は`MyModule`のクラスを要素にもつ配列を渡してやればよいです。

次に、依存性注入用の関数を定義します。`fun inject(任意の引数名: DIするクラス型)`で定義します。今回の場合、`Character`クラスをインジェクトするので、

```kotlin
@Component(modules = [MyModule::class])
interface MyComponent {
    fun inject(character: Character)
}
```

となります。これはあくまでコンポーネントを定義しただけです。実際の依存性注入は手動でやる必要があります。もうひとふんばり！

このコンポーネントを定義すると、`DaggerMyComponent`というのができてるはずです。`Daggerコンポーネント名`の命名規則に従います。こちらを用いてコンポーネントをビルドします。

```kotlin
val component = DaggerMyComponent.builder()
                    .myModules(MyModules())
                    .build()
```

こちらのコンポーネントには先程定義した`inject(character: Character)`メソッドが実装されていますので、そちらを呼び出してインジェクトします。

```kotlin
val character = Character()
component.inject(character)
```

これで`Armer`クラスと`Weapon`クラスのインスタンスが注入されました。これ、実際にやっていることは

```kotlin
val character = Character()
character.armer = Armer()
character.weapon = Weapon()
```

と変わりません。`component`が外側に出ているのが気に食わない？そうですね。`init`の中に突っ込んでしまえばいいのではないでしょうか。

```kotlin
open class Character {

    @Inject lateinit var armer: Armer
    @Inject lateinit var weapon: Weapon

    private val component = DaggerMyComponent.builder()
                                .myModules(MyModules())
                                .build()

    init {
        this.component.inject(this)
    }
}
```

こうすれば、

```kotlin
val character = Character()
```
で自動でインジェクトされますね。

# DI、完全に理解しましたか

結構強引に進めちゃった気がしていますが、どうでしょう。前は単語を聞いただけで頭が痛くなっていた**Dependency Injection**、完全に理解できたのではないでしょうか。

完全に理解したあとは、挫折が待っているかもしれません。Daggerの使い方がようわからん！内部挙動がようわからん！色々苦労するかもしれません。でも、今回の記事で多少なりDIに対する恐怖心が薄れたのであれば、非常に嬉しく思います。

ではでは！よいプログラミングライフを。DI知りたて、Dagger知りたてほやほやの未熟者ですので、何かしらとんでもない誤解をしているかもしれません。もし何かしら間違ってるとかおかしいとかありましたら、ぜひ容赦なく首突っ込んでください。問題なさそうだったら、いいね or コメントいただけると非常に安心します！

# 参考文献

- Kotlinで DI （Dependency Injection）~ Dagger 編 - Qiita ( https://qiita.com/sudachi808/items/a05237e1294639ea41dd )
- Android での依存関係インジェクション  |  Android デベロッパー  |  Android Developers ( https://developer.android.com/training/dependency-injection?hl=ja )
- Dagger の基本  |  Android デベロッパー  |  Android Developers ( https://developer.android.com/training/dependency-injection/dagger-basics?hl=ja )