Dependency Injection Container :: iopeni - Think of C#

요즈음 들어 이 DI Pattern에 상당한 관심을 갖게 되었습니다.


이 포스트의 내용은 상당히 주관적인 내용들이기 때문에 제가 잘못 공부 하여 적는 내용들이 있을 지도 모르겠습니다.


잘못된 부분이 있다면 아낌없는 지적을..... 부탁 드립니다.


일단 Dependency Injection 이란게 무엇인지 알아야 겠죠..


전통적인(???) 이라고 해야 할지 모르겠으나, 오래된 프로그래 개발 방법들을 보면 제어를 담당하고 있는 핵심 Core는 해당 프로그램의 모든 Type을 알고 있어야 했습니다.


예를 들자면 아주 오래된 이야기 입니다만 Windows 이전이 DOS 라는 OS를 사용할 당시엔 화면에 무엇인가 출력 하기 위하여 각종 그래픽 카드들의 드라이버를 어플리케이션이 구현 하여, 프로그램에 탑재 해야 했습니다. 더불어 프린터로 출력 하기 위해서는 어플리케이션에서 각종 프린터 드라이버를 탑재 해야 했으며, 음악을 플레이 하기 위해서 각종 사운드 카드 드라이버를 프로그램에 탑재 하여야 했습니다.


그런데 Windows 라는 OS가 발표 되면서 사실 프로그램 개발자는 각종 디바이스 드라이버를 신경 쓰지 않아도 되는 시대가 도래 했죠. 


모든 디바이스 드라이버는 윈도우가 탑재 하였고 그게 어떤 디바이스 드라이버든지 응용 프로그램에서는 신경 쓰지 않고 화면에 출력 또는 프로그램에 출력, 음악 연주를 하는 세상이 Windows를 통해서 도래 하였습니다.


이런 시대가 도래 함으로서 개발자는 상당히 많은 부분의 부담을 덜어도 되었는데 하나의 출력물을 출력 하기 위하여 HP의 프린터인지 Epson의 프린터인지 LG 프린터인지 신경 쓰지 않아도 되는 정말 편리한 세상이 된 것이죠. 


이런 형태를 하나의 Dependency Injection(의존성 주입) 패턴이라고 봐도 무방 합니다.


즉 어플리케이션은 OS에 어떤 프린터가 설치 되어 있는지 몰라도 되는 상황이 된 것이죠 결국 출력 하기 위해서는 Print 라는 명령문만 날려주면 출력이 이루어지는 세상 말이죠. 


이 DI Pattern 을 구현하고 있는 프레임웍들이 상당히 많은데 사실 이런 용어를 제일 먼저 이야기 한 분은 이 시대의 개발 선구자 중 한명인 마틴 파울러 라는 분입니다.


마틴 파울러가 Inverse of Controls(IoC) 제어 역행화 방법론을 제일 먼저 소개 하였으며, 이것이 많은 개발자들에게 영감을 주어 정말 많은 프레임웍이 세상에 등장 하게 되었죠. 


많은 사람들에게 DI 와 IoC가 같은 레벨의 방법론으로 인지 되고 있으나 사실 DI에 비하여 IoC가 조금 더 추상적인 내용 입니다.


DI 패턴을 공부 하기 위하여, 우리가 제일 먼저 알고 있어야 하는 것은 OOP의 Interface 입니다.


눈치 빠른 분들께선 뭐 당연한 이야기네 라고 말씀 하시겠지만. Interface라는 것이 어떤 타입이든 관계 없이 해당 타입의 메소드 만 존재 한다면 타입 캐스팅이 필요 없이 사용할 수 있는 메커니즘 때문 이라는건 누구나 주지 하고 있는 사실 일 것입니다.


뭐 이쯤해서 서론은 마치기로 하고 몇가지 패턴들에 대해서 이야기 해 보도록 하겠습니다.


GoF의 디자인 패턴 중 Factory 패턴을 보게 되면 이 패턴이 이야기 하고 있는 것은 여러개의 동일한 행위를 하는 여러 타입의 객체를 중앙 집중화 할 수 있는 방법입니다.


회사의 규모에 따라 하나의 회사에는 여러명의 사원이 존재 합니다.


여러명의 사원은 각기 다른 업무를 수행하게 되겠죠.. 영업, 개발, 연구, 경원지원 등등등..... 과 같이 말이죠.


만약 한명의 개인의 급여를 계산 하는 프로그램이 있다고 가정 한다면 급여를 계산 하는 메인 프로세서는 이 사람의 부서, 직책, 직위, 시간외 업무 수당, 실적, 보너스 .. 등등 많은 것들을 고려 하고 있어야 할 것입니다. 


급여 계산을 수행 하고자 하는 메인 프로그램이 모든 사원에게 기본급을 계산 하는 룰은 같다고 가정 하고 각각의 부서별로 다른 급여 계산을 하는 비지니스 모델이라고 한다면, Employee 라는 추상 클래스로서 기본급을 계산 하는 Type을 생성 하고 이 Employee 라는 클래스를 상속 받는 부서별 Class를 작성하여 비지니스 로직을 분리 하고 이 객체를 좀 더 쉽게 생성 중앙 집중화 할 수 있도록 하는 Factory Pattern 을 사용하게 될 것입니다.


컨트롤러의 입장에서 바라 본다면 이 패턴의 문제점은 다음과 같을 것입니다.

어찌 되었든 컨트롤러 입장에서 바라 볼 때, 컨트롤러는 급여 계산을 하기 위하여 어떤 부서가 있는지 명시적 타입을 알고 있어야 할 것입니다.


이것은 DI 패턴이라고 할 수 없죠. 그래서 제시된 방법론이 ServiceLocator 라는 패턴 입니다.


이 ServiceLocator의 핵심은 다음과 같은 코드 입니다.


public class ServiceLocator
{

    private IDictionary<string, object> registeredTypes = new Dictionary<string, object>();

    public void Register<T>(string ServiceName, T obj)
    { 
        registeredTypes.Add(ServiceName, obj);
    }

    public T Locate<T>(string ServiceName)
    {
        return (T)registeredTypes[ServiceName];
    }
}

이 코드를 보면 Dictionary의 Key를 string 타입으로 지정 한 것을 볼 수 있습니다. 즉 각각의 부서명을 이용하여 실제 Object를 취득 하게 됨을 알 수 있습니다.


결국 메인 컨트롤러는 명시적 타입을 알지 못해도 되는 효과를 얻기는 했으나.....


두번째 정말 커다란 문제가 있죠.


만약 회사가 발전하게 되고 회사의 부서가 점점 늘어 나게 될 경우 메인 컨트롤러는 각각의 부서를 Register 하기 위한 코드가 부담 스러워 지게 될 것입니다.


역시 이 또한 Factory 패턴과 별반 다를게 없어 보입니다.


이것을 개선 하기 위하여 작성된 IoC 컨테이너의 핵심 코드를 보도록 하겠습니다.



public class IoCContainer
{

    private IDictionary<Type, object> registeredTypes = new Dictionary<Type, object>();

    public void ADD<T>(T instance)
    { 
        registeredTypes.Add(typeof(T), instance);
    }

    public T GetInstance<T>()
    {
        return (T)registeredTypes[typeof(T)];
    }
}

ServiceLocator 패턴의 핵심 코드와 별반 다르지 않습니다.


그런데 말이죠... 이 코드의 유용함이란.. 정말 이루 말 할 수 없겠네요.  이것으로 DI Container 의 기초 정리는 마무리....... 합니다.

Posted by 프로그래머란 카페인을 코드로 변환하는 기계다
,