행복한 아빠

Dependency Injection-1 본문

SW디자인

Dependency Injection-1

행복한아빠 2009.12.30 09:49
[무엇이 문제인가]   [IoC&DI]   [실전에서]

Spring 프레임워크나 EJB3를 쓰다보면 Dependency Injection(이하 DI)에 대한 이야기가 많이 나오고 있다. 뿐만 아니라 근래에 나오는 프레임워크(Struts2, Hibernate, Grails, ...)들도 기본으로 D.I를 지원하는 추세이다.
D.I의 정확한 의미를 알아보겠다.

무엇이 문제인가?

Wiring
객체의 힘 - 추상화, 다형성
객체지향프로그램(OOP)의 위대함으로 추상화에 있다. 객체를 사용하는 클라이언트(Caller)를 실제 사용하는 객체가 뭔지 몰라도 객체의 인터페이스만 잡고 일을 시킬 수 있다.
여기에서 클라이언트가 잡고 있는 객체를 클라이언트 모르게 바꾸어도 그 코드는 잘 동작하고 동일한 인터페이스라도 실제 객체(concrete class)가 어떤 것인지에 따라 그 동작 방법을 바꿀 수 있다. 이게 OO에서 잘 알려진 다형성(polymorphism)이다.

Wiring
객체는 보통 홀로 동작하지 않는다. 쓸만한 객체가 작성되었다면 최소한 그것을 사용하는 클라이언트는 있어야 할 것이다. 이와 같이 객체들은 서로 협력하여 목적을 달성하기 위해 다른 객체의 참조를 가지고 이를 통해 객체간의 체인이 형성된다. 이를 wiring이라 한다.
사용자 삽입 이미지
추상화의 힘을 사용하기 위해 보통 인터페이스나 추상(abstract 또는 virtual) 클래스를 이용하여 객체간 참조한다. 이제 이 추상화된 참조에 실제 사용할 클래스들을 할당하여 연결하여야 하는 문제가 남아있다.

의도하지 않은 커플링(coupling)
이런 추상화의 힘을 이용하기 위해 객체를 사용하는 클라이언트(caller)를 객체의 인터페이스만을 잡고 있지만 사용할 객체를 생성하기 위해 new 연산자를 사용하게 된다.
이런! new 연산자에 의해 원하지 않게 구체적인 클래스가 의존관계가 형성되게 된다.
사용자 삽입 이미지

위의 그림의 예를 들면 CallerClass는 다음과 같은 코드를 가질 수 있다.
public CallerClass {
    Interface if;
    void doSomething() {
        if = new ConcreteA(); // or if = new ConcreteB()
        ....
       if.xxx();
    }
}
이렇게 의도하지 않은 의존관계를 해결하기 위해 주로 생성과 관련된 패턴을 사용하여 객체 생성을 클라이언트(CallerClass)로부터 분리하기도 한다. 더 좋은 방법은 없을까?

순진한 코더의 예제
다음에 설명할 DI의 개념 이해를 위해 굉장히 간단한 예제로 이야기 할 것이다. 예제는 다음 그림과 같이 임의의 저장소에서 영화목록을 읽고 특정 감독의 영화목록을 추출하는 프로그램이다.
저장소는 CSV(Comma Separated Volume) 파일이 될 수도 있고, DB나 다른 형태가 될 수도 있다. 임의의 저장소에서 찾는 동작을 MovieFinder 인터페이스로 정의하고 이것을 구현한다. MovieLister는 이것을 사용한다.

MovieFinder
public interface MovieFinder {
    List findAll();
}

MovieLister
class MovieLister...
    private MovieFinder finder;
    public MovieLister() {
        finder = new CSVMovieFinder(“movies1.txt”);
    }
    public Movie[] moviesDirectedBy(String arg) {
        List allMovies = finder.findAll();
        for (Iterator it = allMovies.iterator(); it.hasNext();) {
            Movie movie = (Movie) it.next();
            if (!movie.getDirector().equals(arg)) it.remove();
        }
        return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
   }

MovieFinder를 적절히 추상화했지만 위에서 보듯 MovieLister는 의도하지 않게 CVSMovieFinder와 강한 커플링을 형성하고 있다.
사용자 삽입 이미지
이러한 문제를 어떻게 풀 것인가?

계속 ...

참조: http://martinfowler.com/articles/injection.html 
신고

'SW디자인' 카테고리의 다른 글

빚 장부를 관리하십니까?  (7) 2010.04.26
알고리즘 보다는 구조에 집중하세요  (9) 2010.04.05
Dependency Injection-1  (5) 2009.12.30
AOP와 filter  (2) 2009.11.17
클래스 설계에서 "관계" 집중 조명  (0) 2008.03.16
Dependency Injection-3  (0) 2008.03.15
5 Comments
댓글쓰기 폼