개발/Android

[Android] Clean Architecture With Pokedex (feat. Jetpack Compose, Hilt) - 2

du.it.ddu 2022. 7. 9. 15:25

이번 포스팅은 Clean architecture의 가장 안쪽 레이어인 Domain 레이어를 구현할 것이다.
즉, 이전 포스팅에서 생성한 domain 모듈을 구현한다.

먼저 entity를 구현해보도록 하겠다.
포켓몬 도감은 포켓몬들을 리스트업하고 상세한 내용을 볼 수 있는 기능을 갖는다.
따라서 포켓몬 리스트를 구성할 Entity와 포켓몬 상세를 표현할 Entity가 필요하다.
아래와 같은 Entity 코드를 작성한다.

data class PokemonEntity(
    val id: Int,
    val name: String,
    val imageUrl: String
)

data class PokemonDetailEntity(
    val id: Int,
    val name: String,
    val imageUrl: String,
    val weight: Int,
    val height: Int,
    val stats: List<PokemonStatEntity>,
    val types: List<PokemonTypeEntity>
)

data class PokemonStatEntity(
    val name: String,
    val stat: Int
) {
    val progress: Float
        get() = stat.div(300f)
}

enum class PokemonTypeEntity(
    val type: String
) {
    NORMAL("normal"),
    FIRE("fire"),
    WATER("water"),
    ELECTRIC("electric"),
    GRASS("grass"),
    ICE("ice"),
    FIGHTING("fighting"),
    POISON("poison"),
    GROUND("ground"),
    FLYING("flying"),
    PSYCHIC("psychic"),
    BUG("bug"),
    ROCK("rock"),
    GHOST("ghost"),
    DRAGON("dragon"),
    DARK("dark"),
    STEEL("steel"),
    FAIRY("fairy")
}

 이제 이 Entity를 획득할 수 있는 Repository interface를 구현한다.

interface PokemonRepository {
    fun getPokemonPagingSource(
        limit: Int
    ) : Flow<PagingData<PokemonEntity>>

    suspend fun getPokemonDetail(name: String) : PokemonDetailEntity
}

이 interface를 data 레이어에서 구현하여 사용하게 된다.
이제 이 Repository를 통해 포켓몬 목록과 포켓몬 상세를 얻는 UseCase를 작성한다.

class GetPokemonListUseCase @Inject constructor(
    private val pokemonRepository: PokemonRepository
) {
    operator fun invoke(
        limit: Int,
    ) = pokemonRepository.getPokemonPagingSource(limit)
}

class GetPokemonUseCase @Inject constructor(
    private val pokemonRepository: PokemonRepository
) {
    suspend operator fun invoke(
        name: String
    ): PokemonDetailEntity = withContext(Dispatchers.IO) {
        pokemonRepository.getPokemonDetail(name)
    }
}

여기까지 작성하면 domain 레이어의 구현은 끝이 난다.
코드가 길거나 어려운 부분은 없었다.

이 프로젝트에서 의존성 주입을 위해 Hilt를 사용하므로, DI 모듈을 아래와 같이 작성한다.

@Module
@InstallIn(SingletonComponent::class)
object UseCaseModule {
    @Provides
    @Singleton
    fun provideGetPokemonListUseCase(
        pokemonRepository: PokemonRepository
    ): GetPokemonListUseCase = GetPokemonListUseCase(pokemonRepository)

    @Provides
    @Singleton
    fun provideGetPokemonUseCase(
        pokemonRepository: PokemonRepository
    ): GetPokemonUseCase = GetPokemonUseCase(pokemonRepository)
}

Hilt를 통해 정말 쉽게 의존성 주입을 할 수 있다.
다음은 이 domain 레이어를 활용하여 data 레이어를 구현할 것이다.
data 레이어는 Repository interface를 구현하여 presentation에서 entity를 얻을 수 있도록 한다.

domain 레이어의 전체 코드는 아래 깃허브에서 확인할 수 있다.
https://github.com/DuItDDu/Android_CleanArchitecture_Pokedex/tree/master/domain

반응형