본문 바로가기

Android Library

[Android Library] Hilt (1) - 의존성 주입 (Dependency Injection)

안녕하세요.

오늘은 Jetpack Library 중 Hilt에 대해 알아보겠습니다.


개념

객체 지향 프로그래밍에서 객체 간의 의존성을 관리하는 방법입니다.

의존성

한 객체에 의해서 다른 객체가 영향을 받는 것을 의존성이라고 합니다

  • CPU -> Computer
  • Phone -> House (IOT)

코드 상으로 표현하면 아래와 같습니다.

class House {
    val phone: Phone = Phone()
}

class Phone {
    
}

class House는 class Phone을 사용합니다.

=> House는 Phone에 의존적입니다.

 

문제점

두 클래스는 강하게 결합되어 있습니다.

 

하지만 Phone은 한 종류만 있는게 아니죠.

A 회사에서 만든 Phone으로 House를 제어하고 싶으면 아래처럼 코드를 변경해야 합니다.

class House {
    // val phone: Phone = Phone()
    val phone: Phone_A = Phone_A()
}

class Phone_A {
    
}

 

프로그램 코드를 고쳐 위와 같이 바꿔줘야 합니다.

=> 프로그램의 유연성이 떨어지는 문제가 있습니다.


의존성 주입

클래스를 내부에서 만드는 것이 아닌, 외부에서 만들어 주입하는 방식입니다.

 

위에서는 class House 내부에 class Phone을 생성했는데,

의존성 주입은 외부에서 Phone을 만들어서 House 내부로 넣어줍니다.

종류

1. 생성자 주입

의존성을 생성자를 통해 주입하는 방식입니다.

interface Phone {
    fun getControl()
}

class Phone_A : Phone {
    override fun getControl() {
        println("getting a control using Phone A")
    }
}

class Phone_B : Phone {
    override fun getControl() {
        println("getting a control using Phone B")
    }
}

class House(private val phone: Phone) {
    fun getPhoneControl() {
        phone.getControl()
    }
}

fun main() {
    val phoneA = Phone_A()
    val houseA = House(phoneA)
    houseA.getPhoneControl() // 출력: Making a call using Phone A

    val phoneB = Phone_B()
    val houseB = House(phoneB)
    houseB.getPhoneControl() // 출력: Making a call using Phone B
}

 

2. 메서드 주입

의존성을 메서드를 통해 주입하는 방식입니다.

interface Phone {
    fun getControl()
}

class Phone_A : Phone {
    override fun getControl() {
        println("getting a control using Phone A")
    }
}

class Phone_B : Phone {
    override fun getControl() {
        println("getting a control using Phone B")
    }
}

class House {
    fun getPhoneControl(phone: Phone) {
        phone.getControl()
    }
}

fun main() {
    val phoneA = Phone_A()
    val house = House()

    house.getPhoneControl(phoneA) // 출력: Making a call using Phone A

    val phoneB = Phone_B()
    house.getPhoneControl(phoneB) // 출력: Making a call using Phone B
}

 

IoC (Inversion of Control)

의존성 주입하는 부분을 Container 라고 합니다.

(위 코드에서는 main 부분이 Container에 해당)

 

House Class 안에서 제어권을 갖던게

-> Container가 제어권을 가지게 됩니다.

=> 그래서 IoC 라고 합니다.

 

이러한 Container를 Ioc Container 라고 합니다.

Container를 singleton이나 생명 주기 안에서 하나만 생성해서 관리할 수도 있습니다.

=> 리소스 낭비가 줄어드는 장점이 있습니다.


장점

1. 유지 관리성

DI를 사용하면 의존성이 외부에서 주입됩니다.

=> 클래스 간의 결합도가 낮아집니다.

=> 코드의 유지 관리, 변경이 쉬워집니다.

 

2. 테스트 용이성

의존성을 주입할 수 있습니다.

=> 테스트할 때 가짜 객체를 주입하여 테스트하기 용이합니다.

=> Unit Test 작성이 편리합니다.

 

3. 재사용성

의존성 주입을 통해 독립적으로 구성된 컴포넌트를 재사용하기 쉽습니다.

=> 코드의 중복을 줄이고 효율성을 높입니다.

 

4. 유연성

의존성을 외부에서 주입합니다.

=> runtime 때 다른 의존성을 주입함으로써 동적으로 동작을 변경할 수 있습니다.


Reference

의존성 주입 3분만에 이해하기 (Dependency Injection, Inversion of Control)

의존성 주입이란 무엇이며 왜 필요한가?

 

의존성 주입이란 무엇이며 왜 필요한가?

목표 의존성 주입이 무엇인지 이해한다. 의존성 주입이 왜 필요한지 이해한다. 의존성 주입이란? 의존성 주입이란 클래스간 의존성을 클래스 외부에서 주입하는 것을 뜻한다. 의존성 주입 그 자

kotlinworld.com

[Spring] 의존관계 주입(Dependency Injection), 의존성 주입, DI란?

 

[Spring] 의존관계 주입(Dependency Injection), 의존성 주입, DI란?

의존관계(Dependency)란? 의존관계 주입(Dependency Injection)에 대하여 알아보기 전에 의존관계가 무엇인지 알아야 한다. 의존관계는 의존 대상 B가 변하면, 그것이 A에 영향을 미칠 때 A는 B와 의존관계

code-lab1.tistory.com