본문 바로가기
back/spring

[번역]Inversion of Control Containers and the Dependency Injection pattern - Martin Fowler

by juniKang 2022. 5. 8.

원문 : https://martinfowler.com/articles/injection.html

자바스크립트 커뮤니티에는 협력하는 애플리케이션안에 다른 프로젝트들로부터 컴포넌트들을 모으는 것을 도우기위한 가벼운 컨테이너들의 러쉬가 있어왔다.

 

자바스크립트 커뮤니티에서는 서로 다른 프로젝트의 컴포넌트를 하나의 응집력 있는 어플리케이션으로 조립할 수 있도록 도와주는 경량화된 컨테이너를 앞다투어 만들고 있다. 이 컨테이너들이 기본적으로 연결을 수행하는 일반적인 패턴은, 매우 일반적인 이름으로 대표되는 개념인 "Inversion of Control"이다. 이 글에서, "Dependency Injection"이라는 좀 더 구체적인 이름으로 이 패턴이 어떻게 동작하는지 파볼것이고,  "Service Locator alternative"와 비교해볼 것이다. 설정을 사용으로부터 분리하는 원칙보다 둘 중 하나를 선택하는 것이 덜 중요하다.

 


Inversion of Control

컨테이너들이 "Inversion of Control"을 구현했기 때문에 유용하다는 말에대해 나는 어리둥절하다. Inversion of Control은 프레임워크의 보편적인 특성이다. 그래서 경령화 컨테이너들이 Inversion of Control을 사용하기 때문에 특별하다는 말은 내 차가 바퀴가 있어서 특별하다는 말과 같다.

 

중점적인 문제는 "컨트롤의 어떤 면을 뒤집었는가?" 이다. inversion of control을 처음 접했을 때, 유저 인터페이스가 주요 컨트롤이었다. 이전 유저 인터페이스는 애플리케이션 프로그램에 의해 컨트롤됐다. "Enter name", "enter address" 같은 명령어 시퀀스를 사용할 수 있다(you would have);  프로그램이 프롬프트(prompt)를 구동하고, 각 응답을 수신한다. 그래픽(또는 화면 기반) UI를 사용한 UI 프레임워크는 메인 루프가 포함되며, 프로그램은 대신 화면의 다양한 필드에 대한 이벤트 핸드러를 제공한다. 프로그램의 주요 컨트롤이 거꾸로 프레임워크로 이동되었다. 

 

이 새로운 유형의 컨테이너(new breed of containers) 의 반전(inversion)은 플러그인 구현을 찾는 방법에 관한 것이다. 내 이전 예제에서는 리스너가 파인더 현체를 직접 인스턴스화를 해서 찾았다. 이건 파인더가 플러그인으로 존재하는걸 막는다. 이 컨테이너들이 사용하는 접근방식은, 플로그인의 모든 사용자가 별도의 어셈블러 모듈이 리스너로 구현체를 삽입할 수 있도록 하는 몇가지 규칙을 따르도록 하는 것이다(follows some convention).

 

그 결과로, 나는 이 패턴을 위한 좀더 구체적인 이름이 필요하다고 생각한다. Inversion of Control은 너무 일반적잉 용어여서, 사람들이 혼동할 것이다. 다양한 IoC 지지자들과의 많은 논의 결과, 우리는 "Dependency Injeciton" 이라는 이름을 정의했다.

 

이제부터 dependency injection의 다양한 형태에 대해 이야할 것이다. 하지만 이건 짚고 넘어가겠다. 어플리케이션 클래스로에서 플러그인 구현체에대한 의존성을 없애기 위한유일한 방법은 아니다. 시도할 수 있는 다른 방법은 Service Locator가 있다. 이건 Dependency Injection에 대한 설명을 끝낸 후에 다루겠다.

 


Forms of Dependency Injection

Dependecny Injection의 베이직 아이디어는 분리된 객체인 어셈블러를 갖는 것이다. 파인더 인터페이스를 위한 적절한 구현체로 리스너 클래스안에 필드를 거주시킨다. 그림2의 선을 따라 의존성 다이어그램이 생성된다.

depedency injection의 세 가지 주요 스타일이 있다. 내가 사용하는 명칭은 Constructor Injection, Setter Injection, 그리고 Interface Injection 이다. 계속 읽어보면, 이것들에 대해 타입1 IoC (interface injection), 타입2 IoC (setter injeciton), 타입3 IoC (constructor injection)을 듣게 될 것이다. 숫자로 기억하는건 기억하기 어려워서, 이런 이름을 사용했다.

 

Setter Injection with Spring

스프링 프레임워크는 엔터프라이즈 자바를 위한 넓은 범위의 프레임워크이다. tracsactions, persitence frameworks, web application development, JDBC를 위한 추상 계층을 포함한다. constructor와 setter injection을 지원하지만, 개발자들은 setter injection을 보다 선호하는 경향이 있다. - 그리고 이 예제에서 적절한 선택이다.

 

movie liter가 injection을 허용하도록 하기 위해(To get... to accept), 나는 서비스에 대한 setting method를 정의한다.

class MovieLister...
  private MovieFinder finder;
  public void setFinder(MovieFinder finder) {
    this.finder = finder;
  }

비슷하게, filname을 위한 setter를 정의한다.

class ColonMovieFinder...
  public void setFilename(String filename) {
    this.filename = filename;
  }

세번째 스텝은 files를 위한 설정을 셋업하는것이다. 스프링은 XML파일과 코드를통한 설정을 지원한다. 하지만 XML이 기대되는 방식이다.

<beans>
  <bean id="MovieListr" class"spring.MovieLister">
    <property name="finder">
      <ref local="MovieFinder" />
    </property>
  </bean>
  <bean id="MovieFinder" class="spring.ColonMovieFinder">
    <property name="filename">
      <value>movies1.txt</value>
    </property>
  </bean>
</beans>

테스트는 이렇게 한다.

public void testWithSpring() throws Exception {
  ApplicationContext cxt = new FileSystemXmlApplicationContext("spring.xml");
  MovieLister lister = (MovieLister) ctx.getBean("MovieLister");
  Movie[] movies = lister.moviesDeirectedBy("Sergio Leone");
  assertEquals("Once Upon a Time in the West", movies[0].getTitle());
}

 

 

댓글