늦은 프로그래밍 이야기

DI (의존성 주입) 본문

내일배움캠프/Spring

DI (의존성 주입)

한정규 2022. 12. 21. 00:41

DI란?

  • DI는 Dependency Injection의 줄임말
  • 의존성 주입, 의존관계 주입

Dependency (의존관계)

“A가 B를 의존한다”는 표현의 의미

  • 의존대상 B가 변하면, 그것이 A에 영향을 미친다.
  • 즉, B의 기능이 추가 또는 변경되거나 형식이 바뀌면 그 영향이 A에 미친다.

햄버거 가게 예시

  • 햄버거 가게 요리사는 햄버거 레시피에 의존한다.
  • 햄버거 레시피가 변화하게 되었을 때, 변화된 레시피에 따라 요리사는 햄버거를 만드는 방법을 수정해야 한다.
  • 레시피의 변화가 요리사의 행위에 영향을 미쳤기 때문에, “요리사는 레시피에 의존한다”고 말할 수 있다.
  • 코드로 표현
class BurgerChef {
	private HamBurgerRecipe hamBurgerRecipe;

	public BurgerChef() {
		hamBurgerRecipe = new HamBurgerRecipe();
	}
}

의존관계를 인터페이스로 추상화하기

  • 위 BurgerChef 예시의 구현에서는 HamBurgerRecipe만을 의존할 수 있는 구조로 되어있다.
  • 더 다양한 BurgerRecipe를 의존 받을 수 있게 구현하려면 인터페이스로 추상화 해야 한다.
class BurgerChef {
	private BurgerRecipe burgerRecipe;

	public BurgerChef() {
		burgerRecipe = new HamBurgerRecipe();
		// burgerRecipe = new CheeseBurgerRecipe();
		// burgerRecipe = new ChickenBurgerRecipe();
	}
}

interface BurgerRecipe {
	newBurger();
	// 이외의 다양한 메소드
}

class HamBurgerRecipe implements BurgerRecipe {
	public Burger new Burger() {
		return new HamBurger();
	}
	// ...
}
  • 의존관계를 인터페이스로 추상화하게 되면, 더 다양한 의존관계를 맺을 수 있고, 실제 구현 클래스와의 관계가 느슨해지고, 결합도가 낮아진다.

Dependency Injection

  • 지금까지의 구현에서는 BurgerChef 내부적으로 의존관계인 BurgerRecipe가 어떤 값을 가질지 직접 정하고 있다.
  • 만약 어떤 BurgerRecipe를 만들지를 버거 가게 사장님이 정하는 상황을 가정한다.
  • 즉, BurgerChef가 의존하고 있는 BurgerRecipe를 외부(사장님)에서 결정하고 주입하는 것이다.
  • 이처럼 그 의존관계를 외부에서 결정하고 주입하는 것이 DI(의존관계 주입)이다.
  • 다음의 3가지 조건을 충족하는 작업을 의존관계 주입이라 말한다.
    • 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스만 의존하고 있어야 한다.
    • 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제 3의 존재가 결정한다.
    • 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어진다.

DI 구현 방법

  • DI는 의존관계를 외부에서 결정하는 것이기 때문에 클래스 변수를 결정하는 방법들이 곧 DI를 구현하는 방법이다.
  • 런타임 시점의 의존관계를 외부에서 주입하여 DI 구현이 완성된다.
    • 생성자를 이용
    class BurgerChef {
    	private BurgerRecipe burgerRecipe;
    
    	public BurgerChef(BurgerRecipe burgerRecipe) {
    		this.burgerRecipe = burgerRecipe;
    	}
    }
    
    class BurgerRestaurantOwner {
    	private BurgerChef burgerChef = new BurgerChef(new HamburgerRecipe());
    
    	public void changeMenu() {
    		burgerCHef = new BurgerChef(new CheeseBurgerRecipe());
    	}
    }
    
    • 메소드를 이용 (대표적으로 Setter)
    class BurgerChef {
    	private BurgerRecipe burgerRecipe = new HamburgerRecipe();
    	
    	public void setBurgerRecipe(BurgerRecipe burgerRecipe) {
    		this.burgerRecipe = burgerRecipe;
    	}
    }
    
    class BurgerRestaurantOwner {
    	private BurgerChef burgerChef = new BuergerChef();
    
    	public void changeMenu() {
    		burgerChef.setBurgerRecipe(new CheeseBurgerRecipe());
    	}
    }
    

DI 장점

  • 의존성이 줄어든다.
  • 앞서 설명했듯이, 의존한다는 것은 그 의존대상의 변화에 취약하다는 것이다. (대상이 변화하였을 때, 이에 맞게 수정해야함) DI로 구현하게 되었을 때, 주입받는 대상이 변하더라도 그 구현 자체를 수정할 일이 없거나 줄어들게 된다.
  • 재사용성이 높은 코드가 된다.
  • 기존에 BurgerChef 내부에서만 사용되었던 BurgerRecipe를 별도로 구분하여 구현하면, 다른 클래스에서 재사용할 수가 있다.
  • 테스트하기 좋은 코드가 된다.
  • BurgerRecipe의 테스트를 BurgerChef 테스트와 분리하여 진행할 수 있다.
  • 가독성이 높아진다.
  • BurgerRecipe의 기능들을 별도로 분리하게 되어 자연스레 가독성이 높아진다.

출처 :

의존관계 주입(Dependency Injection) 쉽게 이해하기

 

의존관계 주입(Dependency Injection) 쉽게 이해하기

이번 글에서는 DI(의존성 주입, 의존관계 주입)의 개념을 설명한다.

tecoble.techcourse.co.kr


'내일배움캠프 > Spring' 카테고리의 다른 글

POJO  (0) 2022.12.23
IoC 컨테이너  (0) 2022.12.21
Annotation  (1) 2022.12.21
UnsatisfiedDependencyException 에러 해결  (0) 2022.12.16
Spring MVC  (0) 2022.12.07
Comments