1 분 소요

의존성 주입(Dependency Injection, DI) 이란?

DI란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 다이나믹하게 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.

Dependency 의존관계란?

“A가 B를 의존한다” 라는 표현은 “의존대상 B가 변하면, 그것이 A에 영향을 미친다” 라고 해석할 수 있다.

DI1

두 객체 간의 관계(의존성)를 맺어주는 것을 의존성 주입이라고 하며 생성자 주입, 필드 주입, setter 주입 등 다양한 주입 방법이 있다.

※ Spring4 부터는 생성자 주입을 권장

public class PetOwner {
    private Dog dog;

    public PetOwner(){
        dog = new Dog();
    }
}

public class Dog {

}

위와 같은 예시는 크게 다음과 같은 문제점을 갖는다.

1) 두 클래스가 강하게 결합되어 있다.
PetOwner가 Dog 가 아닌 Cat을 원할 경우 PetOwner의 코드를 수정해야 한다. 다른 동물을 원할때마다 매번 수정해야한다. 즉, 유연성이 떨어진다.

2) 객체들 간의 관계가 아니라 클래스 간의 관계가 맺어지고 있다.
PetOwner와 Dog는 객체들 간의 관계가 아니라 클래스들 간의 관계가 맺어져 있다는 문제가 있다. 올바른 객체지향적 설계라면 객체들 간에 관계가 맺어져야 하지만 현재는 PetOwner클래스와 Dog 클래스가 관계를 맺고있다. 객체들 간에 관계가 맺어졌다면 다른 객체의 구체 클래스(Dog인지 Cat인지 등)를 전혀 알지 못하더라도, (해당 클래스가 인터페이스를 구현했다면) 인터페이스 타입(AnimalType)으로 사용할 수 있다.

이런 문제를 해결하기 위해선 우선 다형성이 필요하다. Dog, Cat 등 여러 동물을 하나로 표현하기 위해서 AnimalType 이라는 interface가 필요하다. 그리고 Dog 와 같은 클래스에서 AnimalType 인터페이스를 구현해준다.

public interface AnimalType{

}

public class Dog implements AnimalType{

}

그 다음 AnimalType 와 Dog 가 강하게 연결되어 있는 부분을 제거해줘야 한다. 이를 제거하기 위해 다음과 같이 외부에서 주입받아야 한다.

public class PetOwner{
    private AnimalType animal;

    public PetOwner(AnimalType animal){
        this.animal = animal;
    }
}

※ 참고 다음 세 가지 조건을 충족 하는 작업을 의존성 주입이라 한다.
● 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스만 의존하고 있어야 한다.
● 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제3의 존재가 결정한다.
● 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어진다.

DI 장점

1) 의존성이 줄어든다.
주입받는 대상이 변하더라도 그 구현 자체를 수정할 일이 없거나 줄어들게됨.

2) 재사용성이 높은 코드가 된다.
PetOwner 내부에서만 사용되었던 AnimalType 을 별도로 구현하면, 다른 클래스에서 재사용할 수 있다.

3) 테스트하기 좋은 코드가 된다.
AnimalType의 테스트를 PetOwner 테스트와 분리하여 진행할 수 있다. Mock 객체를 주입하여 실제 구현체 대신 테스트에 사용할 수 있다.

4) 가독성이 높아진다.
AnimalType의 기능들을 별도로 분리하게 되어 자연스럽게 가독성이 높아진다.

태그:

카테고리:

업데이트:

댓글남기기