미분류 - 5주차 공부1
카테고리: unclassified
태그: 미분류
의존성 주입 (Dependency Injection)
의존성 주입(DI)는 필요한 객체를 직접 생성하지 않고 외부에서 넣어주는 방식으로 다음과 같은 이점을 가지고 있다.
- 코드 재사용 가능
- 리팩터링 편의성
- 테스트 편의성
의존성 주입 (종속 항목 삽입, DI, Dependency Injection)이란?
클래스에는 흔히 다른 클래스 참조가 필요하다. 예를 들어 Car 클래스는 Engine 클래스 참조가 필요할 수 있다. 이처럼 필요한 클래스를 종속 항목이라고 하며, 이 예에서 Car 클래스가 실행되기 위해서는 Engine 클래스의 인스턴스가 있어야 한다.
클래스가 필요한 객체를 얻는 방법은 크게 세가지가 있다.
- 클래스가 필요한 종속 항목을 생성하는 방법.
- 다른 곳에서 객체를 가져오는 방법.
- 객체를 매개변수로 제공받는 방법.
이 중 세 번째 방법이 바로 DI이다. 이 방법을 이용하면 클래스 인스턴스가 자체적으로 종속 항목을 가지는 대신 외부 클래스로 부터 종속 항목을 전달 받아 내부에 제공한다.
다음은 DI 없이 Car 자체에서 Engine을 생성하는 예시이다.
class Car {
private val engine = Engine()
fun start() {
engine.start()
}
}
fun main(args: Array) {
val car = Car()
car.start()
}
위의 방법은 다음과 같은 문제를 가질 수 있다.
- Car 인스턴스는 한 가지 유형의 Engine을 사용하므로 서브클래스 또는 대체 구현을 쉽게 사용할 수 없다. Car가 자체 Engine을 구성했다면 Gas 및 Electric 유형의 엔진에 동일한 Car를 재사용하는 대신 두 가지 유형의 Car를 생성해야 한다. 즉 코드의 재사용성이 떨어진다.
- 강력한 Engine 종속 항목 의존성은 테스트를 더욱 어렵게 만든다. Car는 실제 Engine 인스턴스를 사용하므로 다양한 테스트 사례에서 테스트 더블을 사용하여 Engine을 수정할 수 없다.
다음과 같이 Car의 각 인스턴스를 초기화 시 자체 Engine 객체를 구성하는 대신 Engine 객체를 생성자의 매개변수로 받는 것으로 위와 같은 문제를 해결할 수 있다. 그리고 이 방법이 바로 DI(의존성 주입, 종속 항목 삽입)기법이다.
class Car(private val engine: Engine) {
fun start() {
engine.start()
}
}
fun main(args: Array) {
val engine = Engine()
val car = Car(engine)
car.start()
}
이런 DI에는 두 가지 방법이 있다.
- 생성자 주입
- 필드 주입
생성자 주입은 위의 예시 처럼 클래스의 종속 항목을 생성자에 전달하는 방법이다. 하지만 Activity나 Fragment와 같은 특정 Android 프레임워크 클래스는 시스템애서 인스턴스화하므로 생성자 주입이 불가능 하다. 이런 경우 필드 삽입을 사용하여 종속 항목은 클래스가 생성된 후 인스턴스화되도록 할 수 있다. 다음은 필드 주입의 예시이다.
class Car {
lateinit var engine: Engine
fun start() {
engine.start()
}
}
fun main(args: Array) {
val car = Car()
car.engine = Engine()
car.start()
}
Reference