[CS] DI(Dependency Injection) 특징 및 DI 주입 방법

hyewon jeong·2023년 3월 28일
0

TIL

목록 보기
110/138

1. DI(Dependency Injection)에 대한 설명과 해당 기술의 장점에 대해 설명해주세요.

1-1.DI(Dependency Injection)?

IoC(제어의 역전)은
프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것으로 코드의 최종호출은 개발자가 제어하는 것이 아닌 프레임워크의 내부에서 결정된 대로 이루어집니다.


의존성 주입
객체가 다른 객체에 의존할 때 이를 외부에서 주입해주는 방식을 말합니다. 즉, 객체가 필요로 하는 의존성을 직접 생성하는 것이 아니라, 외부에서 생성된 객체를 주입해주는 것입니다.

DI는 대표적으로 스프링 프레임워크에서 지원하는 IoC의 형태로 클래스 사이의 의존관계를 빈 설정 정보를 바탕으로 컨테이너가 자동으로 연결해줍니다.

이때 스프링 컨테이너 ApplicationContext를 이용하여 설정 정보를 생성, 등록하고 필요한 객체를 생성자 혹은 setter 혹은 필드를 통해 주입합니다.

🍕피자 가게 요리사는 피자 레시피에 의존한다.
피자 레시피가 변화하게 되었을때
변화된 레시피에 따라서 요리사는 피자 만드법을 수정해야한다.
레시피의 변화가 요리사의 행위에 영향을 미쳤기 때문에 요리사는 레시피에 의존한다고 말할 수 있다.


만약 어떤 피자가게의 레시피는 피자가게 요리사가 아니라, 피자 가게 사장님이 정하는 상황을 상상해보자.
피자가게 요리사가 의존하고 있는 피자레시피는 외부(사장님)에서 결정하고 주입한느 것

1-2 DI 주입 방식 3가지

생성자 삽입, Setter를 이용한 메소드 매개 변수 삽입, 필드 주입이 있습니다.

1) Setter주입

@Service
public class BurgerService {

    private BurgerRecipe burgerRecipe;

        @Autowired
    public void setBurgerRecipe(BurgerRecipe burgerRecipe) {
        this.burgerRecipe = burgerRecipe;
    }
}

setter를 사용한 주입이다.

장점

  • 선택적인 의존성을 사용할 수 있다.

단점

  • 선택적인 의존성을 사용할 수 있다는 것은 BurgerService(한 서비스로직)에 모든 구현체를 주입하지 않아도 burgerRecipe(@setter를 주입한) 객체를 생성할 수 있고, 객체의 메소드를 호출할 수 있다. 즉, 주입받지 않은 구현체를 사용하는 메소드에서 NPE가 발생한다.
  • 순환 참조 문제가 발생할 수 있다.

2) 필드 주입

@Service
public class BurgerService {

    @Autowired
    private BurgerRecipe burgerRecipe;
}

변수 선업부에 @Autowired 어노테이션을 붙입니다.

@Autowired 를 사용하는데

장점

  • 사용하기 편하다.

단점

  • 단일 책임 원칙 위반 가능성이 커진다.
    @Autowired 선언만 하면 되므로 의존성을 주입하기 쉽다.
    따라서, 하나의 클래스가 많은 책임을 갖게 될 가능성이 높다.
  • 불변성을 보장할 수 없다.
  • 순환 참조가 발생할 수 있다.
  • 외부에서 변경이 불가능하여 테스트 하기 힘듭니다. DI 프레임워크 없이는 작동하기 힘들며, 주로 애플리케이션과 관계없는 테스트코드나 @Configuration 같은 스프링 설정 목적으로 사용합니다.

3) 생성자 주입

생성자 호출시점에 딱 1번만 호출되는 것을 보장하며 불변, 필수 의존관계에 사용합니다.

@Service
public class BurgerService {

    private BurgerRecipe burgerRecipe;

        @Autowired
    public BurgerRecipe(BurgerRecipe burgerRecipe) {
        this.burgerRecipe = burgerRecipe;
    }
}

생성자에 @Autowired 어노테이션을 붙여 의존성을 주입받을 수 있으며, 가장 권장되는 주입 방식이다.

장점

  • 의존 관계를 모두 주입 해야만 객체 생성이 가능하므로 NPE를 방지할 수 있다.
  • 불변성을 보장할 수 있다.

[Spring] Spring IoC와 DI란?

1-2.DI 장점

결합도 감소

DI를 사용하면 객체 간의 결합도를 낮출 수 있습니다. 객체 간의 결합도가 낮아지면 코드의 유지보수성과 확장성이 개선됩니다.

테스트 용이성

DI를 사용하면 테스트 용이성이 높아집니다. 의존하는 객체를 모의(mock) 객체로 대체하여 테스트할 수 있습니다. 이는 의존하는 객체가 아직 구현되지 않았더라도 테스트를 진행할 수 있게 해줍니다.

코드의 재사용성

DI를 사용하면 객체 간의 의존성이 명시적으로 표현되므로, 재사용성이 높아집니다. 의존성을 주입하는 방식으로 객체를 조립할 수 있으므로, 동일한 의존성을 가지는 객체를 생성할 때 코드의 중복을 줄일 수 있습니다.

유지보수성

DI를 사용하면 의존성을 관리하는 책임을 DI 컨테이너에게 위임하므로, 코드의 유지보수성이 개선됩니다. 의존성이 변경되더라도 DI 컨테이너에서 의존성을 관리하기 때문에, 변경이 필요한 코드를 수정하는 일을 줄일 수 있습니다.

유연성

DI를 사용하면 객체를 동적으로 생성하고 의존성을 주입할 수 있으므로, 유연성이 높아집니다. 객체 생성 방식이 변경되더라도, DI 컨테이너에서 객체를 생성하고 의존성을 주입하므로, 코드 수정이 필요하지 않습니다.

요약하자면

이러한 방식을 적용하면 객체 간의 결합도를 낮출 수 있으며, 유지보수성, 확장성, 테스트 용이성 등을 개선할 수 있습니다. 또한 의존성을 관리하는 책임을 전적으로 DI 컨테이너에게 위임함으로써 코드의 중복을 줄이고, 유연하고 모듈화된 코드를 작성할 수 있습니다.

예를 들어 호텔클래스와 룸 클래스가 있을때 룸 클래스는 호텔클래스에 의존성이 생기게 되는데, 이때 DI를 사용하여 룸 클래스에서 호텔클래스의 인스턴스를 매개변수로 사용하여 주입받으면 의존성을 제거하여 유지 보수가 간결 해집니다.

profile
개발자꿈나무

0개의 댓글