DI + Hilt(1)

햄햄·2022년 6월 18일
0

DI

목록 보기
1/1
post-thumbnail

DI??

클래스에는 흔히 다른 클래스 참조가 필요합니다. 예를 들어, Car 클래스에 Engine 클래스 참조가 필요할 수 있습니다. 이처럼 필요한 클래스를 디펜던시(종속 항목)이라고 합니다. 이 예에서 Car 클래스가 실행되기 위해서는 Engine 클래스의 인스턴스가 있어야합니다.

클래스가 자체적으로 디펜던시를 얻는 대신, 클래스의 디펜던시를 제공받는것을 DI라고 합니다.

class Car {

    private val engine = Engine()

    fun start() {
        engine.start()
    }
}

fun main(args: Array) {
    val car = Car()
    car.start()
}

위 코드는 Car 클래스가 Engine을 구성하기 때문에 DI의 예가 아닙니다.
위 코드는 어느 문제가 있을 수 있을까요?

  • CarEngine은 밀접하게 연결되어있습니다. Car 인스턴스는 한 가지 유형의 Engine을 사용하므로 GasElectric 유형의 엔진에 동일한 Car를 재사용하는 대신 두 가지 유형의 Car을 생성해야합니다.
  • Engine의 강력한 디펜던시는 테스트를 어렵게 만듭니다. Car는 실제 Engine 인스턴스를 사용하므로 테스트 더블을 사용해 Engine을 수정해 테스트할 수 없습니다.

    테스트 더블?
    테스트를 진행하기 어려운 경우 이를 대신해 테스트를 진행할 수 있도록 만들어주는 객체를 사용해 테스트를 하는 것 입니다.

Android에서 DI를 실행하는 방법?

Android에서 DI를 실행하는 두 가지 주요 방법은 다음과 같습니다.

  • 생성자 삽입 : 클래스의 디펜던시를 생성자에 전달합니다. 예는 아래와 같습니다.
class Car(private val engine: Engine) {
    fun start() {
        engine.start()
    }
}

fun main(args: Array) {
    val engine = Engine()
    val car = Car(engine)
    car.start()
}
  • 필드 삽입(or setter 삽입) : 액티비티 및 프래그먼트와 같은 Android 프레임워크 클래스는 시스템에서 인스턴스화하므로 생성자 삽입이 불가능합니다. 필드 삽입을 사용하면 디펜던시는 클래스가 생성된 후 인스턴스화합니다. 예는 아래와 같습니다.
class Car {
    lateinit var engine: Engine

    fun start() {
        engine.start()
    }
}

fun main(args: Array) {
    val car = Car()
    car.engine = Engine()
    car.start()
}

DI 라이브러리, Hilt

위 예에서는 라이브러리를 사용하지 않고 다양한 클래스의 디펜던시를 수동으로 생성, 제공 및 관리했습니다. 위 예의 Car 클래스는 하나의 디펜던시를 가졌지만, 더 복잡한 예에서는 위와 같이 수동으로 디펜던시를 삽입 하기에 어려움이 있을 수 있습니다.
따라서 수동으로 디펜던시를 삽입하는 작업을 간단하게 하기 위해 다양한 DI 라이브러리가 제공됩니다.

그 중 Hilt는 Android에서 DI를 위한 Jetpack 권장 라이브러리입니다. Hilt는 프로젝트의 모든 Android 클래스에 컨테이너를 제공하고 수명 주기를 자동으로 관리함으로써 애플리케이션에서 DI를 사용하는 표준 방법을 제공합니다.

요약

DI는 다음과 같은 이점을 제공합니다.

  • 클래스 재사용 가능 및 종속 항목 분리: 디펜던시의 구현을 쉽게 교체할 수 있습니다. 제어 반전(inversion of control)으로 인해 코드 재사용이 개선되었으며 클래스가 더 이상 디펜던시의 생성을 제어하지 않습니다.

    inversion of control(IoC)
    전통적인 프로그래밍에서 흐름은 프로그래머가 작성한 프로그램이 외부 라이브러리의 코드를 호출해 이용한다. 하지만 제어 반전이 적용된 구조에서는 외부 라이브러리의 코드가 프로그래머가 작성한 코드를 호출한다.
    https://ko.wikipedia.org/wiki/제어_반전

  • 리팩토링 편의성: 디펜던시는 API Surface 영역의 검증할 수 있는 요소가 되므로 세부적인 구현 정보로 숨겨지지 않고 객체 생성 타임 또는 컴파일 타임에 확인할 수 있습니다.

  • 테스트 편의성: 클래스는 디펜던시를 관리하지 않으므로 테스트 시 다양한 구현을 전달하여 다양한 사례를 테스트할 수 있습니다.

0개의 댓글