삽질의 현장/- TypeScript

의존성 주입이란 무엇인가?

shovelman 2019. 10. 12. 15:08

의존성 주입에 대해 리서칭하는 중 답변이 이해하기 좋아 댓글로 오고 간 내용을 정리해보았다.

참고: 의존성 주입이 뭔가요?

 

의존성 주입이란,
'필요한게 있을 때 무엇이 필요하다고 선언하면 알아서 제공해줘' 즉, 관심의 분리(seperation of concern)을 의미한다.
일반적으로 class의 instance를 다음과 같이 생성하여 사용한다.

MyClass myClass = new MyClass();

instance 생성 비용이 크다거나, 여러 군데서 사용한다거나, 일일히 생성할 필요가 있는지 등에 대한 이유로
instance의 생성을 컨테이너에 맡겨서 일괄적으로 진행하고, life-cycle 관리 역시 컨테이너에 맡겨버리게 된다.

 

instance의 생성 및 관리 주체가 내가 아니라 컨테이너가 되기 때문에 Invension Of Control(제어의 역전)이 되는 것이고
그 방법론 중에 하나로 Dependency of Injection(의존성 주입)이 일어나는 것이다.

(의존성 주입이 대체하는 가장 대표적인 패턴은 서비스 로케이터(service locator)이다.)

 

가능하면 하나의 컴포넌트는 단일한 관점에 집중할 수 있도록 설계하는 것이 좋기 때문에,
게시물 서비스는 게시물 관리라는 관점, 혹은 관심사(concern)만 신경쓰게 하려면
앞서 말한 데이터베이스와 관련된 부분은 유틸 클래스나 레지스트리 등의 모양으로 외부화 하는 접근이 가능하고,
그것이 이전에 유행하던 서비스 로케이터 패턴의 핵심이다.

 

그러다보니 한걸음 더 나가서 커넥션 풀 같은 의존성은 로케이터 같은 데서 가져올 것이 아니라
아예 외부에서 알아서 던져주면 깔끔하겠다는 생각이 든 것이고,
그래서 제어 역전(Invension of Control), 혹은 의존성 주입 패턴이 생겨나게 된것이다.

 

즉, '가능하면 하나의 컴포넌트는 단일한 관점에 집중할 수 있도록 설계하는 것'(단일 책임 원칙)을 지키기 위해 생겨난 패턴이다.

 

 

instance 생성 시점에 필요한 정보와 instance 사용 시점에 필요한 정보가 다를 수 있다.
실제로 어떤 코드를 설계할 때, 사용자가 어떤 행동을 할 지 예측할 수 없을 때가 있다.
예를 들어 마우스 클릭과 관련한 클래스를 구현했다고 가정해보자.

class Mouse {
  function click() {
    // click event
  }
}

구현 시점에서 사용자가 어떤 클릭을 할지 알 수 없을 것이다.
그래서 해당 부분을 insterface로 남겨두고 구현 시점을 미뤄버리는 것이다.

classMouse {
  interfaceOnClickListener {
    onClickListener(x, y);
  }
  OnClickListeneronClickListener;

  // 생성자를 통해서 onClick 인스턴스 주입
  publicfunction(OnClickListeneronClickListener) {
    this.onClickListener = onClickListener;
  }

  onClick() {
    // mouse 포인터의 x, y 위치를 얻어오는 메서드 생략
    const x = getPositionX();
    const y = getPositionY();

    // onClickListener 인스턴스에 클릭되었다는 정보를 넘겨준다.
    onClickListener.onClickListener(x, y);
  }
}

구현 시점에 알 수 없는 정보나, 각종 환경에 따라서 달라질 수 있는 값등을 분리해서 생각한다.
더 간단한 예로, 게시판을 관리하는 서비스가 곧바로 데이터베이스를 통해 게시물을 조회하고 등록한다고 가정해보자.


의존성 주입이 없다면 데이터베이스 연결 정보를 설정에서 찾아오고 커넥션 풀을 구성하는 등의
'관점', 혹은'역할(role)'이나 '책임(responsibility)'이 모두 해당 게시물 서비스에 전가된다.