본문 바로가기
Development/Android

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

by du.it.ddu 2022. 7. 9.
반응형

이번 포스팅은 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

반응형