Dependency Injection
Setiap project wajib menggunakan Dependency Injection (DI) untuk memudahkan testing dan decoupling.
Rekomendasi per Platform
| Platform | DI Framework | Tipe |
|---|---|---|
| Android | Hilt (recommended) / Koin | Compile-time / Runtime |
| iOS | Factory / swift-dependencies | Runtime |
| Flutter | GetIt + Injectable | Runtime |
| React Native | Manual DI / tsyringe | Manual / Runtime |
Prinsip
- Constructor Injection — Selalu inject dependency melalui constructor.
- Program to Interface — Inject interface, bukan implementasi langsung.
- Single Responsibility — Setiap module DI bertanggung jawab atas satu scope.
- Android (Hilt)
- Flutter (GetIt)
- React Native
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindUserRepository(
impl: UserRepositoryImpl
): UserRepository
}
@Module
@InstallIn(ViewModelComponent::class)
object UseCaseModule {
@Provides
fun provideGetUserUseCase(
repository: UserRepository
): GetUserUseCase = GetUserUseCase(repository)
}
final getIt = GetIt.instance;
void setupDI() {
// Data sources
getIt.registerLazySingleton<UserRemoteDataSource>(
() => UserRemoteDataSourceImpl(getIt()),
);
// Repositories
getIt.registerLazySingleton<UserRepository>(
() => UserRepositoryImpl(getIt(), getIt()),
);
// Use cases
getIt.registerFactory(() => GetUserUseCase(getIt()));
// Cubits
getIt.registerFactory(() => UserCubit(getIt()));
}
// Simple manual DI container
class DIContainer {
private static instance: DIContainer;
private constructor() {}
static getInstance(): DIContainer {
if (!DIContainer.instance) {
DIContainer.instance = new DIContainer();
}
return DIContainer.instance;
}
get userRepository(): UserRepository {
return new UserRepositoryImpl(
new UserApiService(this.apiClient),
new UserLocalStorage(),
);
}
get getUserUseCase(): GetUserUseCase {
return new GetUserUseCase(this.userRepository);
}
}