Android
Design

Dependency Injectionについて調べてみた

DIとは?

Dependencyというのは、依存性のことです。
例えば、以下の例を見てみてください。

sample.kt
class Car(val name: String) 
class User(val name: String, val car: Car)

UserクラスはCarクラスを保持しています。
つまり、UserクラスはCarクラスに依存していますね。
CarはUserの依存性です。

Injectionというのは注入のことです。
上記の例で言えば、UserクラスにCarを渡すことですね。
Userというクラスに必要としている、Carを注入しています。

依存性注入というのは、Userクラスが自分でCarを作るのではなく、外からUserにCarを渡すということです。
そうすることで、UserとCarの結びつきが薄くなります。(Carにはinterfaceを使うことでより結びつきを弱められます)
例えば、Userが他のCarオブジェクトが必要になってもUserクラスを変更する必要はありません。
Userに渡すCarオブジェクトを変更すれば良いだけです。

このおかげで、UserはCarに対する以下のような知識を減らすことができます。
1. Carの生成方法を知る必要がありません。
2. 実際にどのCarを使っているのかを知る必要がありません。(interfaceを使っているという前提で、どの具象クラスを使っているのかを知る必要がないの意)

Injectionの方法とは?

主に以下の3つの方法があります。
1. constructor
2. setter
3. interface

Dependency Injectionデザインパターンで解決したいこと

  1. 依存性オブジェクトの生成方法とクライアントコードの独立をさせたい(異なるオブジェクトが必要になった時に、クライアントコードを都度変更したくない)
  2. オブジェクトの生成方法を別ファイルで管理したい

Androidチームの現状にはどう役立つのか?

  1. テストのカバー率を上げられる?
  2. アーキテクチャにより沿った実装にできる?

1. テストのカバー率を上げられる?

Androidには、View系のほとんどのリソースを管理しているContextというオブジェクトがいます。
例えば、以下のような処理をする時に、このContextが必要になります。
1. LocalDBの操作をする
2. 画面表示系のほとんどの操作をする

みてもらえれば分かる通り、presentation層のこともやるし、data層のこともやっています。
そのため、本当にアーキテクチャに沿った実装をやろうとすると、presentation/domain/data層全てにおいてContextを参照できる必要があります。
しかし、これはテストをするには不便です。(なぜ不便なのかはわかっていない。とりあえず、Contextがいるとテストできないという認識。)
configurationファイルにオブジェクトの生成処理を書くことができるとすれば、LocalDBを参照するクラスで、Contextを持つ必要がなくなります。
なぜなら、LocalDBを外部から作成して注入することができるからです。
そうなるとdomainとdata層に関してもバッチリテストを書くことができるようになります。

2. アーキテクチャに「より」忠実な実装にできる?

現在は上で挙げた理由から、ローカルDBへの操作がViewで行われてしまっています。
ローカルDBへの操作をするためにContextが必要ではなくなれば、ローカルDBが本来あるべきであるdata層に移植できます。

そうすると、viewがentityを触ることも無くすことができるので、新しいアーキテクチャへの展望が見えてくるのだろうと思います。