Kotlin / Android開発で学ぶ Dependency Injection(DI)入門
最近Androidアプリ開発の勉強をしている中で、Hiltを学習しよう!と思ったときにDIの理解が足りなかったため学習に至りました。
目次
- DI(Dependency Injection)とは何か
- なぜDIが必要なのか
- コード例で理解するDI
- モック/スタブとテストの関係
- HiltなどDIフレームワークとの関係
DI(依存性注入)とは?
Dependency Injection(依存性注入) とは、「クラスが必要とする依存オブジェクトを、外部から渡してあげる」設計手法です。
例:Car
クラスが Engine
を必要とする場合、Car クラスが自分で Engine を生成するのではなく、外部から Engine インスタンスを渡すようにします。
// Engineインターフェース(設計図)
interface Engine {
fun start()
}
// MainEngineクラス(具体的な実装)
class MainEngine : Engine {
override fun start() {
println("Engine started")
}
}
// Carクラス(Engineインターフェースに依存)
class Car(private val engine: Engine) {
fun drive() {
engine.start()
}
}
イメージでいうと、エンジニアAさんとエンジニアBさんがいたとします。
・エンジニアAさん⇒Carクラスを作成
・エンジニアBさん⇒Engineクラスを作成
こうすることで、仮にエンジンインスタンスを変更したいときにはBさんのコードをいじるだけですむ。つまり保守性が上がるということ。
なぜDIが必要なのか
先ほども言ったようにコードの管理がしやすくなるからです。
責任を分散する、依存関係を緩くすることでコードの修正が簡単になったり、明示的に引数として書くので読みやすくなったりします。
コード例で理解するDI
では、実際にDIありとなしのコードを比較してみましょう。
//DIなし
// Engineの実装クラスを作る
class MainEngine : Engine {
override fun start() {
println("Engine started")
}
}
class Car {
private val engine = MainEngine() // 実装クラスを直接インスタンス化
fun drive() {
engine.start()
}
}
//DIあり(今回の話)
class Car(private val engine: Engine) {
fun drive() {
engine.start()
}
}
// クラスの外で実装クラスのインスタンスを作成して渡す
val engine = MainEngine() // ← 実装クラスのインスタンス
val car = Car(engine) // ← 依存性を注入(DI)
モック/スタブとテストの関係
次にモックとスタブについて簡単に説明します。
スタブ:返り値を固定するための仮の実装
⇒プログラムの振る舞いさえ分かればいい
モック:呼び出しの有無や回数を検証する目的の実装
⇒プログラム実行時の動きまで確認したい
//スタブテスト
class StubEngine : Engine {
override fun start(): String {
return "Stub engine started"
}
}
val stubEngine = StubEngine()
val car = Car(stubEngine)//スタブテスト用エンジンインスタンスを車クラスに渡す
エンジンクラスとは別に、スタブテスト用エンジンクラスも作る。(DI設計)
//モックテスト
class MockEngine : Engine {
var startCalled = false
override fun start(): String {
startCalled = true
return "Mock engine started"
}
}
val mockEngine = MockEngine()
val car = Car(mockEngine)
println(mockEngine.startCalled) // true なら、start() が呼ばれた証拠
モックはスタブと違い、中身のメソッドがちゃんと動くかを確認したい。今回はstart()インスタンスがきちんと動くか確認したい。
HiltなどDIフレームワークとの関係
これまで書いたように、DIはとても重要な設計思想である。そのために楽に、自動的にやってくれるのがHiltなどのDIフレームワークである。
Hiltに関してまた、別の記事でまとめようと思います。
感想
DIはとても大事な設計思想であり、アーキテクチャ手法であることがよく分かりました。
ただ、理解度はまだ7〜8割程度で、どこかニュアンスを間違えている可能性もあります。
もし誤りがあれば、ご指摘いただけるとありがたいです。
今後は今回学んだ内容を基に、Hiltの学習により力を入れていきたいと思います。