Android & Kotlin

Hilt 관련 리펙토링 기록 (@binds @Provides 차이 , UsecaseModule)

쉽코기 2023. 1. 8. 15:39

구조설명 (클린 아키텍처)

1. 클린아키텍처 구조에서 Hilt 를 통해 의존성 주입을 사용하고 있었다.
2. 이때 Repository (Interface) 의 주입을 위해 RepoisotyModule 을 만들어 사용했고 @Provides 를 사용해왔었다.
3. 그리고 Usecase 에서 Ropository 와 ErrorHandler 에 의존했고 이에 따라 각각 UsecaseModule, NetowrkModule 을 정의해주어 사용했다.

class GetSomeUseCase(
    private val repository: Repository,
    private val errorHandler: ErrorHandler
) : BaseUseCase() {...}


    @ErrorHandler
    @Provides
    @Singleton
    fun provideErrorHandler(
        @HttpClient http: OkHttpClient,
        appStorage: AppStorage
    ): ErrorHandler =
        NetErrorHandlerImpl(
            http.retrofit(appStorage.getBackBaseUrl())
        )


    @Provides
    @ViewModelScoped
    fun provideGetSomeUseCase(
        repo: Repository,
        @ErrorHandler errorHandler: ErrorHandler
    ) = CheckUsedAddressUseCase(repo, errorHandler)

    @Provides
    @Singleton
    fun provideRepository(
        apiSevice: Apiservice
    ): Repository =
        RepositoryImpl(apiSevice)

 

 

 

@provides 와 @Binds 차이

외부적으로 기능적 차이를 보이지 않지만 사용법에 차이에서 비록한 차이가 존재한다.

 

1. @Binds / @povides 를 통한 주입 방법 정의 차이

@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {

    @Binds
    @Singleton
    abstract fun bindRepository(
        repository: RepositoryImpl
    ): Repository

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


@Provides
@Singleton
fun provideRepository(
    apiSevice: ApiService
): Repository =
    RepositoryImpl(apiSevice)

 

2. 객체 주입시 사용 방법의 차이

  • @binds 의 경우 @Inject constructor 를 붙여줌으로써 해당 부분에서의 의존성 주입을 명시해주고 @provids 의 경우 그렇지 않고 모듈에서 찾아 주입해주게된다.

이런 제약으로 인해 @binds 는 서드파티 라이브러리에 대한 의존성 주입이 불가하기에 해당 경우엔 @provids 를 사용할 수 밖에 없다.

 

또 아래와 같이 usecaseModule 의 필요성 유무를 결정 짓기도하다. usecase 에서 인터페이스인 Repo 를 의존할 경우 @provids 의 경우 @Inject 키워드를 붙이기 않기때문에 모듈을 반드시 필요로 하지만 @binds 의 경우 @Inject 를 통해 usecase 모듈을 생성을 하지 않아도 된다.

 

그렇다면 @Provids 로 주입 객체를 정의하고 @Inject constructor 를 붙여준다면 usecaseModule 없이 동작할 수 있을까?

실험결과 이것 또한 가능 했다.


class GetSomeUseCase @Inject constructor(
private val Repository: Repository,
@ErrorHandler private val errorHandler: ErrorHandler
) : BaseUseCase() {
fun execute() =
Repository.getSomeUseCase()
.toNetResult(errorHandler)
}

(@binds 를 통한 객체 생성후 주입의 경우 usecaseModule 불필요)

@Provides
@ViewModelScoped
fun provideGetSomeUseCase(
    repo: Repository,
    @ErrorHandler errorHandler: ErrorHandler
) =
    GetSomeUseCase(repo, errorHandler)



class GetSomeUseCase(
private val Repository: Repository,
private val errorHandler: ErrorHandler

) : BaseUseCase() {

(@provids 의 경우 @Inject Constutor 없을 경우 usecaseModule 필요)