[Sample] 카드 인식 모듈화 작업(2)

수호·2025년 11월 19일
post-thumbnail

Payon Module 호출 전 Flow

feature/reader/viewmodel/ReaderViewModel.kt

 cardReaderUseCase(ReaderType.PAYON, tag).collect { result ->
      when(result){
          is CardResult.Loading -> {
              _uiEvent.emit(UiEvent.Loading(result.isLoading))
          }
          is CardResult.Success -> {
              _uiEvent.emit(
                  UiEvent.ShowDialog(
                      "카드인식 성공",
                      "Card : ${Util().bytesToHex(result.data.track2Data)}"
                  )
              )
          }
          is CardResult.Error -> {
              _uiEvent.emit(UiEvent.ShowDialog(result.code, result.message))
          }
      }
  }
core/domain/usecase

class CardReaderUseCase @Inject constructor(
    private val repository: CardReaderRepository
) {
    suspend operator fun invoke(type: ReaderType, tag: Tag): Flow<CardResult> {
        return repository.readCard(type, tag)
    }
}
core/domain/repository

interface CardReaderRepository {
    suspend fun readCard(type: ReaderType, tag: Tag): Flow<CardResult>
}

enum class ReaderType {
    PAYON,
    SAMSUNG_PAY
}
core/data/repository

class CardReaderRepositoryImpl @Inject constructor(
    private val dataSource: CardReaderDataSource
) : CardReaderRepository {
    override suspend fun readCard(type: ReaderType, tag: Tag): Flow<CardResult> {
        return dataSource.readCard(type, tag)
    }
}
core/data/source

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)
    }
}
core/data/source/reader

interface ReaderStrategy {
    suspend fun readCard(tag: Tag): Flow<CardResult>
}

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
    }
}
core/data/di

@Module
@InstallIn(SingletonComponent::class)
object ReaderModule {

    @Provides
    @Singleton
    fun provideCardReaderRepository(
        dataSource: CardReaderDataSource
    ): CardReaderRepository = CardReaderRepositoryImpl(dataSource)

}
  1. payon 결제를 추가하면서 제일 먼저 생각한 것 → 확장성(추후 결제 로직)
  2. 흐름

viewModel → useCase 호출 → repository 호출 → dataSource 호출 → readerFactory에서 type에 따라 payon or samsungPay reader 선택

profile
처음부터 다시 시작!!

0개의 댓글