依存性注入(DI)とは?
DIの概要
依存性注入(Dependency Injection, DI)とは、オブジェクトの依存関係を外部から注入する設計パターンです。DIを活用することで、以下のメリットが得られます。
- コードの再利用性向上:異なるコンポーネント間での依存関係を分離できる。
- テスト容易性の向上:モックやスタブを簡単に差し替えられる。
- 保守性の向上:依存関係を明示的に管理しやすくなる。
DIの基本概念
DIには主に以下の3つの方法があります。
- コンストラクタインジェクション(推奨)
- フィールドインジェクション
- メソッドインジェクション
Kotlinでは、主に コンストラクタインジェクション が推奨されます。
class Engine
class Car(private val engine: Engine) {
fun start() {
println("Car is starting with engine: $engine")
}
}
この例では、Car
クラスのコンストラクタで Engine
インスタンスを受け取り、依存性を注入しています。
Hiltによる依存性注入
Hiltとは?
Hiltは、Googleが提供する Dagger ベースの依存性注入フレームワークで、AndroidアプリのDIを簡単に実装できます。
Hiltのメリット
- 公式サポート:GoogleがAndroid向けに最適化。
- コードの簡潔化:Daggerよりも設定がシンプル。
- ライフサイクルに統合:ActivityやFragmentに簡単に適用可能。
Hiltのセットアップ
build.gradle.kts
に以下を追加します。
dependencies {
implementation("com.google.dagger:hilt-android:2.40.5")
kapt("com.google.dagger:hilt-compiler:2.40.5")
}
アプリの Application
クラスに @HiltAndroidApp
を追加します。
@HiltAndroidApp
class MyApplication : Application()
Hiltを使った依存性注入
モジュールの定義
Hiltでは、@Module
と @InstallIn
アノテーションを使って依存関係を提供します。
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
fun provideEngine(): Engine {
return Engine()
}
}
コンストラクタインジェクション
@Inject
アノテーションを使用して依存性を注入できます。
class Car @Inject constructor(private val engine: Engine) {
fun start() {
println("Car is starting with engine: $engine")
}
}
Activityへの注入
ActivityやFragmentで @AndroidEntryPoint
を追加し、依存性を注入できます。
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var car: Car
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
car.start()
}
}
Koinによる依存性注入
Koinとは?
Koinは、シンプルなDIフレームワークで、コードのボイラープレートを最小限に抑えられるのが特徴です。
Koinのメリット
- シンプルなAPI:アノテーション不要。
- 設定が簡単:Hiltよりも導入が容易。
- 軽量:Kotlinネイティブにも対応。
Koinのセットアップ
build.gradle.kts
に以下を追加します。
dependencies {
implementation("io.insert-koin:koin-android:3.1.4")
}
アプリの Application
クラスで Koin を初期化します。
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@MyApplication)
modules(appModule)
}
}
}
Koinの使用方法
モジュールの定義
Koinでは module
を使用して依存関係を提供します。
val appModule = module {
single { Engine() }
factory { Car(get()) }
}
Activityへの依存性注入
by inject()
を使用すると、簡単に依存関係を取得できます。
class MainActivity : AppCompatActivity() {
private val car: Car by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
car.start()
}
}
HiltとKoinの比較
比較項目 | Hilt | Koin |
---|---|---|
設定の簡単さ | やや複雑 | シンプル |
パフォーマンス | 高速(Daggerベース) | やや低速(リフレクション使用) |
Kotlinネイティブ対応 | なし | あり |
ボイラープレートの量 | 多め | 少なめ |
HiltはGoogle公式でサポートされており、大規模プロジェクトに向いています。一方、Koinはシンプルな設定が可能で、より軽量なプロジェクトに適しています。
まとめ
本記事では、Kotlinにおける依存性注入(DI)の基本と、Hilt・Koinの導入方法について解説しました。
- DIを使うことで、依存関係を明確化し、コードの保守性を向上させる
- HiltはDaggerベースで公式サポートがあり、Androidアプリに最適
- Koinはシンプルで設定が容易、Kotlinネイティブにも対応
プロジェクトの規模や要件に応じて、適切なDIフレームワークを選択しましょう!