깨알 개념/Android

[Android] Dagger2 - 인터페이스 구현체 주입 (@Binds)

interfacer_han 2024. 6. 25. 05:16

#1 이전 글

 

[Android] Dagger2 - 기초

#1 이전 글 의존성 주입 (Dependency Injection)#1 의존성 주입(Dependency Injection)이란?#1-1 Dependent와 Dependencyfun main() { val car = Car() car.startCar() } class Car { private val engine = Engine() private val airbag = Airbag() private

kenel.tistory.com

위 게시글의 완성된 앱을 일부 수정해서, Interface를 Dependency로 주입해본다.

 

#2 코드 수정 - 직관적인 버전

#2-1 개요

 

[Android] Dagger2 - 매개변수

#1 이전 글 [Android] Dagger2 - @Provides#1 이전 글 [Android] Dagger2 - 기초#1 이전 글 의존성 주입 (Dependency Injection)#1 의존성 주입(Dependency Injection)이란?#1-1 Dependent와 Dependencyfun main() { val car = Car() car.startCar

kenel.tistory.com

위 게시글의 앱을 구현할 줄 안다면, 쉬운 구현 방식이다. Battery 클래스를 인터페이스로 바꾸고, 해당 인터페이스를 구현하는 EcoFriendlyBattery 클래스를 만든다. 그리고 EcoFriendlyBattery를 Dependency로 받고, Battery를 필요로 하는 Dependent에게 반환하는 @Provides 메소드를 만들면 끝이다. 본 게시글에선 @Component.Builder를 따로 작성하지 않는데, 왜냐하면 아래에 나와 있는 의존성 그래프에서 보듯, @Provides 메소드가 요구하는 Dependency가 @Inject에 의해 자동 주입되기 때문이다.

 

#2-2 의존성 그래프

이 경우의 의존성 그래프다.

 

#2-3 Battery.kt 수정

// package com.example.interfacedependency

interface Battery {
    fun startBattery()
}

 

#2-4 EcoFriendlyBattery.kt 생성

// package com.example.interfacedependency

import android.util.Log
import javax.inject.Inject

class EcoFriendlyBattery @Inject constructor() : Battery {
    override fun startBattery() {
        Log.i("interfacer_han", "${this::class.simpleName} is ready")
    }
}

 

#2-5 @Module 클래스 및 @Provide 메소드 생성

// package com.example.interfacedependency

import dagger.Module
import dagger.Provides

@Module
class BatteryModule {

    @Provides
    fun providesEcoFriendlyBattery(ecoFriendlyBattery: EcoFriendlyBattery): Battery {
        return ecoFriendlyBattery
    }
}

 

#2-6 @Component에 @Module 등록

// package com.example.interfacedependency

import dagger.Component

@Component(modules = [BatteryModule::class])
interface CarComponent {
    fun getCar(): Car
}

 

#2-7 작동 확인 (로그 메시지)

Crankshaft is ready
Cylinder is ready
Piston is ready
Engine is ready
Airbag is ready
EcoFriendly
Battery is ready
Car is ready

 

#3 코드 수정 - @Binds 사용

#3-1 개요

@Binds 어노테이션을 이용해 #2를 수정해본다. @Binds는 dagger에서 인터페이스와 그 구현체를 바인딩하는 목적을 가진다. 이 어노테이션을 통해 프로그래머는 특정 인터페이스 타입인 Dependency를 어떤 구현체로 정할 지 명시할 수 있다.

 

#3-2 의존성 그래프

#2-2와 구조가 같다. 구현 방식이 더 간결해졌을 뿐이다.

 

#3-3 BatteryModule.kt 수정

...

@Module
abstract class BatteryModule {

    @Binds
    abstract fun bindsEcoFriendlyBattery(ecoFriendlyBattery: EcoFriendlyBattery): Battery
}

/*

@Module
class BatteryModule {

    @Provides
    fun providesEcoFriendlyBattery(ecoFriendlyBattery: EcoFriendlyBattery): Battery {
        return ecoFriendlyBattery
    }
}

*/

 

#2와 완전히 똑같이 수정하되, BatteryModule.kt만 위와 같이 바꾼다. @Binds 어노테이션은 설계상 문법적으로 반드시 추상 메소드에 붙는다. 어째서일까? @Binds는 이름 그대로 Binding이 목적이기에, 실제로 내부적으로 객체를 생성해 반환하는 비(非)추상 메소드와 함께할 이유가 없기 때문이다. 객체를 생성하는 게 아니라, 이미 생성된 객체(여기서는 Inject된 EcoFriendlyBattery)를 (Battery에) 바인딩하는 게 @Binds 메소드의 역할이다.

 

또, 추상 메소드를 가지기 위해선 추상 클래스여야하므로 @Module 클래스를 추상 클래스로 만든다. dagger 라이브러리는 이러한 추상 @Module 클래스 안에는 반드시 @Binds 추상 메소드가 있을 거라고 인식하고 적절히 처리한다.

 

#3-4 작동 확인 (로그 메시지)

Crankshaft is ready
Cylinder is ready
Piston is ready
Engine is ready
Airbag is ready
EcoFriendly
Battery is ready
Car is ready

 

#4 요약

@Binds는 인터페이스 구현체를 위한 의존성 주입하기 위한 어노테이션이다.

 

#5 완성된 앱

 

android-practice/dagger2/InterfaceDependency at master · Kanmanemone/android-practice

Contribute to Kanmanemone/android-practice development by creating an account on GitHub.

github.com