ViewModel → UseCase → Repository → ReaderFactory → ReaderStrategy(Payon or Samsung)
class CardReaderUseCase @Inject constructor(
private val repository: CardReaderRepository
) {
suspend operator fun invoke(type: ReaderType, tag: Tag): Flow<CardResult> {
return repository.readCard(type, tag)
}
}
→ Hilt는 생성자에 있는 CardReadRepository를 자동으로 주입해 준다.
→ 여기서 Repository는 실제 구현체가 아닌 Interface Type
@Module
@InstallIn(SingletonComponent::class)
object ReaderModule {
@Provides
@Singleton
fun provideCardReaderRepository(
dataSource: CardReaderDataSource
): CardReaderRepository = CardReaderRepositoryImpl(dataSource)
}
CardReaderRepository 타입이 필요하면, CardReaderRepositoryImpl(dataSource)를 생성해서 제공해
class CardReaderRepositoryImpl @Inject constructor(
private val dataSource: CardReaderDataSource
) : CardReaderRepository {
override suspend fun readCard(type: ReaderType, tag: Tag): Flow<CardResult> {
return dataSource.readCard(type, tag)
}
}
→ Hilt는 RepositoryImpl 객체를 만들 때 자동으로 DataSource를 넣어준다.
class CardReaderDataSource @Inject constructor(
private val factory: ReaderFactory
) {
suspend fun readCard(type: ReaderType, tag: Tag): Flow<CardResult> {
val reader = factory.getReader(type)
return reader.readCard(tag)
}
}
→ DataSource을 만들 때 Hilt는 ReaderFactory를 넣어준다.
class ReaderFactory @Inject constructor(
private val payonReader: ReaderStrategy,
private val samsungReader: ReaderStrategy
) {
fun getReader(type: ReaderType): ReaderStrategy = when (type) {
ReaderType.PAYON -> payonReader
ReaderType.SAMSUNG_PAY -> samsungReader
}
}
interface ReaderStrategy {
suspend fun readCard(tag: Tag): Flow<CardResult>
}
💡
Hilt는 어떻게 PayonReader와 SamsungReader를 구분할까?
class ReaderFactory @Inject constructor(
@PayonReaderQualifier private val payonReader: ReaderStrategy,
@SamsungReaderQualifier private val samsungReader: ReaderStrategy
)
→ 보통 각각 @Named 또는 @Qualifier로 구분해야 한다.
→ 현재는 Payon만 있어서 오류가 나지 않지만 SamsungPay까지 있으면 에러가 발생할 것이다.
class PayonReader @Inject constructor(
private val nfcAdapter: PayonNfcAdapter,
private val api: RetrofitPayonApi
) : ReaderStrategy {
override suspend fun readCard(tag: Tag): Flow<CardResult> = flow {
...
}
}
→ Hilt는 PayonReader를 만들 때 필요한 의존성을 넣어준다.
ReaderStrategy → DataSource → Repository → UseCase → ViewModel → UI
ViewModel
↑
CardReaderUseCase (Hilt inject)
↑
CardReaderRepository (Interface)
↑
CardReaderRepositoryImpl (Hilt @Provides binds)
↑
CardReaderDataSource (Hilt inject)
↑
ReaderFactory (Hilt inject)
↑
ReaderStrategy 구현체 2개 (payonReader, samsungReader)