2014년 4월 20일 일요일

의존관계 주입

객체와 객체사이에 의존성이 있다는 것은 어떤 의미인가?

그림 1 은  A가 B에 의존하고 있음을 나타낸다. 의존하고 있다는 것은 무슨 의미인가? A가 B을 사용하고 있다는 것이다. 그래서 B의 변화가  A에 전달이 된다.  A는 B의 클라이언트라고 할 수 있다. 예를 들어 A에서 B에 정의된 메서드를 호출하는 것이다. B에 정의된 메서드가 변경이 되면 당연히 A 에서의 호출부분도 변경이 되어야 한다. 반대로 B는 A에 의존하고 있지 않다. A의 변경은 B에 전달되지 않는다.



그림 1 - 의존관계

의존관계 주입(Dependency Injection)

의존관계 주입은 구체적인 의존 오브젝트와 그것을 사용하는 클라이언트 오브젝트를 런타임시에 연결해주는 작업을 말한다.

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

의존관계 주입의 핵심은 설계 시점에는 알지 못했던 두 오브젝트의 관계를 맺도록 도와주는 제3의 존재가 있다는 것이다. 즉 클라이언트는 자신이 사용할 의존 오브젝트를 직접 생성하지 않고 이는 외부의 제 3의 존재가 결정하게 된다.

그림 2을 보자. Cafe의 성격에 따라 Coffee 만을 파는 일반적인 카페일지도 전통찻집일수도 있다. 그래서  Cafe 라는 클래스는 자신이 주로 파는 음료는 만드는 BeverageMaker 라는 의존 오브젝트를 사용한다. Cafe 라는 클래스만 봐서는 beverageMaker 에 어떤 구체 클래스가 할당이 될지 알 수 없다. 그리고 이것은 Cafe 라는 클래스가 직접 자신이 사용할 BeverateMaker을 선택하지 않고 외부의 제 3의 존재가 결정하게 된다.


그림 2 - Cafe 와 BeverageMaker



여기서는 CafeFactory 라는 클래스가 그 역활을 담당하게 된다. CafeFactory 의 구현은 아래와 같다.



그림 3 - CafeFactory



package iamhereweare.oop.di;

public class CafeFactory {
 
 public Cafe cafe() {
  Cafe cafe = new Cafe();
  cafe.setBeverageMaker(beverageMaker());
  return cafe; 
 }

 private BeverageMaker beverageMaker() {
  return new CoffeeBeverageMaker();
 }
}

코드  CafeFactory 구현

CafeFactory의 beverageMaker() 의 구현에 따라 Cafe에서 사용할 BeverageMaker가 결정이 되게 된다. (Cafe 클래스가 직접 결정하지 않는다.) 이런 것을 제어의 역전이라고 한다.

제어의 역전에서는 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않느다. 당연히 생성하지도 않는다. 또 자신도 어떻게 만들어지고 어디서 사용되는지를 알 수 없다. 모든 제어 권한을 자신이 아닌 다른 대상에게 위임하기 때문이다.

제어의 역전에 대해서는 별도의 포스팅이 있으니 그것을 참고하자. CafeFactory가 하는 일을 일반화해서 만든 것이 스프링의 애플리케이션 컨텍스트, 빈 팩토리, IoC 컨테이너 등이다. 모두 외부에서 오브젝트 사이의 런타임 관계를 맺어주는 책임을 지닌 제 3의 존재라고 볼 수 있다.

참고자료

  • 토비의 스프링 3.1(이일민)
                                                           

댓글 없음:

댓글 쓰기