도움말 번역입니다.
컴포넌트 간의 종속성 관리하기
프리즘 라이브러리에 기반하는 응용프로그램들은 복합 응용프로그램으로, 잠재적으로 많은 느슨하게 결합된 타입들과 서비스들로 구성되어 있습니다. 그것들은 사용자 동작에 기반한 통지를 획득하고 칸텐트에 기여하기 위해서 상호작용할 필요가 있습니다. 그것들은 느슨하게 결합되어 있기 때문에, 요구되는 비즈니스 기능들을 전달하기 위해서 서로 상호작용하고 통신하는 방법을 필요로 합니다.
이 다양한 조각들을 서로 묶기 위해서, 프리즘 라이브러리에 기반한 응용프로그램들은 의존성 주입 컨테이너( dependency injection container )에 의존합니다. 의존성 주입 컨테이너들은 오브젝트 사이의 종속성 결합을 줄여 주는데, 이는 클래스들의 인스턴스들을 생성하는 기능과 컨테이너의 구성에 기반해 그것들의 라이프타임을 관리하는 기능을 제공함으로써 이루어집니다. 오브젝트 생성 동안에, 컨테이너는 오브젝트가 요구하는 모든 종속성들을 주입합니다. 만약 그 종속성들이 아직 생성되지 않았다면, 컨테이너가 먼저 종속성들을 생성하고 결정합니다. 어떤 경우에는, 컨테이너 자체가 종속성으로서 결정될 수 있습니다. 예를 들어, 유니티 응용프로그램 블락( Unity )을 컨테이너로 사용하고 있을 때, 모듈들은 주입된 컨테이너를 가지게 되므로, 그것들은 자신의 뷰와 서비스를 컨테이너에 등록할 수 있습니다.
컨테이너를 사용하는 것은 몇 가지 이점을 지닙니다:
- 컨테이너는 컴포넌트가 자신의 종속성의 위치를 결정하고 그것의 라이프타임을 관리하지 않도록 해 줍니다.
- 컨테이너는 컨포넌트에 영향을 주지 않고 구현된 종속성들이 교체되는 것을 허용합니다.
- 컨테이너는 종속성들을 가상화( mock )하는 것을 허용함으로써 테스트를 용이하게 합니다.
- 컨테이너는 새로운 컴포넌트들이 시스템에 쉽게 추가될 수 있도록 함으로써 유지보수성을 증가시킵니다.
프리즘 라이브러리에 기반한 응용프로그램의 문맥에서는, 컨테이너에 대한 특별한 이점들이 존재합니다:
- 컨테이너는 모듈이 로드될 때 마쥴 종속성들을 마쥴에 주입합니다.
- 컨테이너는 뷰 모델과 뷰를 등록하고 결정하기 위해서 사용됩니다.
- 컨테이너는 뷰 모델을 생성하고 뷰를 주입할 수 있습니다.
- 컨테이너는 영역 관리자와 이벤트 어그리게이터와 같은 복합 서비스들을 주입합니다.
- 컨테이너는 모듈-지정 서비스들을 등록하는데 사용됩니다. 그 서비스는 모듈-지정 기능을 가지고 있습니다.
노트:
프리즘 가이던스의 일부 샘플들은 컨테이너로 유니티 응용프로그램 블락에 의존합니다.다른 코드 샘플들은, 예를 들어 Modularity QuickStarts 와 같은 경우에는, 관리되는 확장성 프레임워크( MEF )를 사용합니다. 프리즘 라이브러리 자체는 컨테이너-지정이 아닙니다. 그리고 그것의 서비스들과 패턴들을 다른 컨테이너와 함께 사용할 수 있습니다. Castle Windsor, StructureMap, Spring.NET 와 같은 컨테이너들이 있습니다.
주요 결정: 의존성 주입 컨테이너 선택하기
프리즘 라이브러리는 의존성 주입 컨테이너를 위한 두 가지 옵션을 제공합니다: Unity 와 MEF. 프리즘은 확장성이 있기 떄문에, 약간 다른 작업을 수행하는 다른 컨테이너들이 대신 사용되는 것을 허용합니다. Unity 와 MEF 는 모두 의존성 주입을 위한 같은 기본 기능을 제공합니다. 그것들이 매우 다르게 동작하고 있음에도 불구하고 말이죠. 두 컨테이너는 다음을 포함하는 일부 기능들을 제공합니다:
- 그것들은 모두 컨테이너에 타입들을 등록합니다.
- 그것들은 모두 등록된 타입들의 인스턴스들을 생성합니다.
- 그것들은 모두 등록된 타입들의 인스턴스들을 생성자에 주입합니다.
- 그것들은 모두 등록된 타입들의 인스턴스들을 프라퍼티들에 주입합니다.
- 그것들은 모두 관리될 필요가 있는 타입들과 종속성들을 표시하기 위해서 선언적인 애트리뷰트들을 가집니다.
- 그것들은 모두 오브젝트 그래프에서 종속성들을 결정합니다.
Unity 는 MEF 가 제공하지 않는 몇 가지 기능들을 제공합니다:
- 그것은 등록없이 concrete 타입들을 결정합니다.
- 그것은 open generics 를 결정합니다.
- 그것은 오브젝트들에 대한 호출을 캡춰하고 대상 오브젝트들에 기능을 추가하기 위해서 인터셉션( interception )을 사용합니다.
MEF 는 Unity 가 제공하지 않는 몇 가지 기능들을 제공합니다:
- 그것은 디렉토리에서 어셈블리를 검색합니다.
- 그것은 XAP 파일 다운로드와 어셈블리 검색을 사용합니다.
- 그것은 속성과 컬렉션을 발견된 새로운 타입들로 재구성합니다.
- 그것은 자동으로 상속된 타입들을 익스포트합니다.
- 그것은 닷넷 프레임워크와 함께 배포됩니다.
이 컨테이너들은 기능과 동작에서 차이점들을 가지고 있습니다. 그러나 프리즘 라이브러리는 둘 다 컨테이너로 작동하게 만들며, 유사한 기능을 제공할 것입니다. 어떤 컨테이너를 사용할 것인지를 고려할 때는, 앞에서 언급한 기능들을 살펴 보고 자신의 시나리오에 잘 맞는 것을 선택하십시오.
컨테이너 사용시 고려 사항들
컨테이너를 사용하기 전에 다음을 고려해야 합니다:
- 컨테이너를 사용할 때 컴포넌트를 등록하고 결정하는데 어떠한 것이 적절한지를 고려하십시오 :
- 컨테이너에 등록하고 인스턴스를 컨테이너로부터 결정하는 것의 성능 부하가 시나리오에서 받아들여질 만한 것인지를 고려하십시오. 예를 들어, 만약 렌더링 메서드의 로컬 영역 안에서 서피스를 그리기 위해 만 개의 폴리곤을 생성할 필요가 있다고 할 때, 모든 폴리곤 인스턴스들을 컨테이너를 통해서 결정하는 비용은 엉청난 성능 부하를 가지게 될 것입니다. 왜냐하면 컨테이너가 각 엔터티를 생성하기 위해서 리플렉션을 사용하기 때문입니다.
- 종속성들이 많거나 깊다면, 생성 비용은 엄청나게 증가할 수 있습니다.
- 컴포넌트가 종속성을 가지고 있지 않거나 다른 타입에 대한 종속성이 아니라면, 그것을 컨테이너에 배치하는 것은 불필요합니다.
- 컴포넌트가 타입에 대해 필수적이며 결코 변하지 않는 단일한 종속성 집합을 가진다면, 그것을 컨테이너에 배치하는 것은 불필요합니다.
- 컴포넌트의 라이프타임이 싱글톤으로 등록되어야 하는지 인스턴스로 등록되어야 하는지를 고려하십시오:
- 컴포넌트가 로깅 서비스와 같이 단일 리소스를 위한 리소스 관리자로서 동작하는 전역 서비스라면, 그것을 싱긆톤으로 등록하는 것을 원할 것입니다.
- 컴포넌트가 다수의 고객에 대한 공유 상태를 제공한다면, 그것을 싱글톤으로 등록하는 것을 원할 것입니다.
- If the object that is being injected needs to have a new instance of it injected each time a dependent object needs one, register it as a non-singleton. 예를 들어, 각 뷰는 아마도 뷰 모델의 새로운 인스턴스를 필요로 할 것입니다.
- 코드를 통해 구성되기를 원하는지 구성( configuration )을 통해 구성되기를 원하는지를 고려하십시오 :
- 서로 다른 모든 서비스들을 중앙에서 관리하고자 한다면, 구성 파일을 통해 컨테이너를 구성하십시오.
- 개별 서비스들을 선택적으로 등록하기를 원한다면, 코드를 통해 컨테이너를 구성하십시오.
- 모듈-레벨 서비스들을 가지고 있다면, 코드를 통해 컨테이너를 구성하는 것을 고려하십시오. 그러면 그 서비스들은 모듈이 로드될 때만 등록됩니다.
노트:
MEF 와 같은 어떤 컨테이너들은 구성 파일을 통해서 구성될 수 없으며, 반드시 코드를 통해 구성되어야만 합니다.
핵심 시나리오들
컨테이너들은 두 가지 주요 목적을 위해서 사용됩니다. 말하자면 등록( registering )과 결정( resolving )입니다.
등록
종속성을 오브젝트에 주입하기 전에, 종속성들의 타입이 컨테이너에 등록될 필요가 있습니다. 타입을 등록하는 것은 보통 컨테이너에 인터페이스와 인터페이스를 구현하는 concrete 타입을 넘기는 것을 포함합니다. 타입과 오브젝트를 등록하기 위한 두 가지 주요 수단이 존재합니다: 코드를 통하거나 구성 파일을 통하는 것입니다. 특정 수단은 컨테이너 별로 다양합니다.
보통, 코드를 통해 컨테이너에 타입과 오브젝트를 등록하는 것은 두 가지 방식이 있습니다:
- 컨테이너에 타입이나 매핑을 등록할 수 있습니다. 적절한 시점에, 컨테이너는 당신이 지정하는 타입의 인스턴스를 빌드할 것입니다.
- 현존하는 오브젝트 인스턴스를 싱글톤으로 컨테이너에 등록할 수 있습니다. 이 컨테이너는 현존하는 오브젝트의 레퍼런스를 반환할 것입니다.
유니티 컨테이너에 타입을 등록하기
초기화 동안에, 타입은 뷰나 서비스와 같은 다른 타입들을 등록할 수 있습니다. 등록은 그것들의 종속성들이 컨테이너를 통해서 제공될 수 있도록 허용하며, 그것들이 다른 타입들로부터 접근 가능하도록 허용합니다. 이를 수행하기 위해서, 타입은 모듈 생성자에 주입된 컨테이너를 가지고 있을 필요가 있습니다. 다음 코드는 Commanding Quickstart 에 있는 OrderModule 타입이 타입을 등록하는 방법에 대해서 보여 줍니다.
어떤 컨테이너를 사용하느냐에 따라, 등록은 구성 파일을 통해 코드 외부에서 수행될 수도 있습니다. 예를 들어, 4장의 "Registering Modules using a Configuration File" 의 "Modulear Application Development" 를 참조하십시오.
노트:
구성 파일에 등록하는 것과 비교했을 때 코드에서 등록하는 것의 이점은 등록이 모듈이 로드될 때만 발생한다는 것입니다.
MEF 를 사용하여 타입을 등록하기
MEF 는 애트리뷰트 기반 시스템을 사용해서 컨테이너에 타입을 등록합니다. 결과적으로, 타입 등록을 컨테이너에 추가하는 것이 단순합니다: 그것은 부가적인 [Export] 애트리뷰트를 타입에 요규합니다. 다음 코드에서 그 예를 볼 수 있습니다.
MEF 를 사용할 때의 또 다른 옵션은 클래스의 인스턴스를 생성하고 개별 인스턴스를 컨테이너에 등록하는 것입니다. Modularity for Silverlight with MEF QuickStart 의 QuickStartBootstrapper 는 ConfigureContainer 메서드에서 이 예를 보여 줍니다.
노트:
MEF 를 컨테이너로 사용할 때, 타입들을 등록하기 위해서 애트리뷰트들을 사용하는 것을 권장합니다.
결정
타입이 등록되면, 그것은 종속성으로서 결정되거나 주입될 수 있습니다. 타입이 결정되고 있을 때, 컨테이너는 새로운 인스턴스를 생성할 필요가 있습니다. 그것은 이 인스턴스들에 종속성들을 주입합니다.
일반적으로, 타입이 결정될 때, 세 가지 일 중에 하나가 발생합니다:
- 타입이 등록되지 않았다면, 컨테이너는 예외를 던집니다.
- 타입이 싱글톤으로 등록되었다면, 컨테이너는 싱글톤 인스턴스를 반환합니다. 그 타입이 처음으로 호출되는 것이라면, 컨테이너는 그것을 생성하고 이후의 호출을 위해서 저장합니다.
- 타입이 싱글톤으로서 등록되지 않았다면, 컨테이너는 새로운 인스턴스를 반환합니다.
유니티를 사용해 인스턴스를 결정하기
다음 코드 예제는 Commanding QuickStart 에서 가져 온 것으로, OrdersEditorView 와 OrdersToolBar 를 해당 영역과 연관시키기 위해서 컨테이너로부터 결정되는 곳이 어디인지를 보여 줍니다.
OrderEditorPresentationModel 생성자는 다음 종속성들을 포함하는데( 주문 저장소와 주문 명령 프락시 ), 그 종속성들은 그것이 결정될 때 주입됩니다..
이전 코드에서 본 생성자 주입과 함께, 유니티는 프라퍼티 주입도 허용합니다. [Dependency] 애트리뷰트가 적용된 모든 프라퍼티들은 오브젝트가 결정될 때 자동적으로 결정되고 주입됩니다.
MEF 를 사용해 인스턴스를 결정하기
다음 코드 예제는 Modularity for Silverlight with MEF QuickStart 에 있는 Bootstrapper 가 쉘의 인스턴스를 획득하는 방법을 보여 줍니다. 콘크리트 타입을 요청하는 대신, 코드는 인터페이스의 인스턴스를 요청할 것입니다.
MEF 에 의해서 결정되는 모든 클래스에서, 생성자 주입을 사용할 수도 있습니다. 그 예가 Modularity for Silverlight with MEF QuickStart 에 있는 ModuleA 인데, 그것은 주입된 ILoggerFacade 와 IModuleTracker 를 가지고 있습니다.
또 다른 옵션은 프라퍼티 주입을 사용하는 것입니다. 그 예는 Modularity for Silverlight with MEF QuickStart 에 있는 ModuleTracker 인데, 그것은 주입된 ILoggerFacade 의 인스턴스를 가지고 있습니다.
노트:
실버라이트에서, 임포트된 프라퍼티들과 필드들은 반드시 퍼블릭이어야만 합니다.
프리즘에서 종속성 주입 컨테이너들과 서비스들을 사용하기
종속성 주입 컨테이너들은, 보통 그냥 "컨테이너"라고 불리는데, 컴포넌트들 간의 종속성을 만족시키기 위해서 사용됩니다; 이 종속성들을 만족시키는 것은 일반적으로 등록과 결정을 포함합니다. 프리즘 라이브러리는 유니티 컨테이너와 MEF 컨테이너를 지원하는데, 그것은 컨테이너-지정은 아닙니다. 이 라이브러리는 IServiceLocator 인터페이스를 통해서 컨테이너에 접근하기 때문에, 컨테이너는 대체될 수 있습니다. 이를 위해서는 당신의 컨테이너가 IServiceLocator 인터페이스를 구현해야만 합니다. 보통, 컨테이너를 대체하고 있을 때, 자신만의 컨테이너-지정 부트스트래퍼를 제공할 필요가 있을 것입니다. IServiceLocator 인터페이스는 Common Service Locator Library 에서 정의됩니다. 이는 종속성 주입 컨테이너나 서비스 로케이터와 같은 IoC( Inversion of Control ) 컨테이너들에 대한 추상을 제공하기 위한 오픈 소스 작업입니다. 이 라이브러리를 사용하는 목적은 특별한 구현에 얽매이지 않고 IoC 와 Service Location 을 위한 지렛대를 제공하기 위함입니다.
프리즘에서 Common Service Locator 구현들
비록 프리즘 라이브러리가 특정 컨테이너를 참조하거나 의존하지 않는다지만, 응용프로그램은 특정 컨테이너에 의존하는 것이 일반적입니다. 이는 특정 응용프로그램이 그 컨테이너를 참조하는 것이 합리적이지만, 프리즘 라이브러리가 컨테이너를 직접적으로 참조하지는 않는다는 것을 의미합니다. 예를 들어, 프리즘에 포함된 StockTrader RI 와 몇 몇 QuickStart 들이 유니티를 컨테이너로 사용합니다. 다른 샘플들과 QuickStart 들은 MEF 를 사용합니다.
IServiceLocator
다음 코드는 IServiceLocator 인터페이스를 보여 줍니다.
서비스 로케이터는 다음 코드에서 보여 주는 확장 메서드들을 사용해서 프리즘 라이브러리 내에서 확장됩니다. IServiceLocator 가 결정을 위해서만 사용되는 것을 볼 수 있으며, 그것은 인스턴스 획득을 위해서 사용됨을 의미합니다; 등록을 위해서 사용되지는 않습니다.
TryResolve 확장 메서드 - 유니티 컨테이너는 지원하지 않음 - 는 결정하려고 하는 이미 등록된 타입의 인스턴스를 반환합니다; 등록되지 않았다면, null 을 반환합니다.
모듈이 로드되는 동안, ModuleInitializer 는 모듈을 결정하기 위해서 IServiceLocator 를 사용합니다. 그 예가 아래에 나와 있습니다.
IServiceLocator 를 사용하는데 고려할 점들
IServiceLocator 는 범용-목적 컨테이너를 위한 수단이 아닙니다. 컨테이너들은 다양한 sematics of usage 를 가지며, 그것은 보통 그 컨테이너가 선택된 이유가 무엇인지를 결정하게 됩니다. 이를 염두에 두고, Stock Trader RI 는 IServiceLocator 를 직접적으로 사용하는 대신에 유니티를 사용합니다. 이는 응용프로그램 개발에 있어서 추천되는 접근법입니다.
다음 상황에서는, IServiceLocator 를 사용하는 것이 적합할지도 모릅니다:
- 당신이 다중 컨테이너를 지원할 필요가 있는 서드-파티 서비스를 설계하는 독립적인 소프트웨어 벤더( ISV, independent software vendor )인 경우.
- 당신이 다중 컨테이너를 사용할 수도 있는 조직에서 사용될 서비스를 설계하고 있는 경우.
더 많은 정보들
컨테이너와 관련한 더 많은 정보들을 원한다면, 아래 문서들을 참조하십시오:
- MSDN 의 "유니티 응용프로그램 블락" : http://www.msdn.com/unity
- 코드 플렉스의 유니티 커뮤니티 : http://www.codeplex.com/unity
- MSDN 의 "관리되는 확장성 프레임워크( MEF ) 개요" : http://msdn.microsoft.com/en-us/library/dd460648.aspx
- 코드 플렉스의 MEF 커뮤니티 : http://mef.codeplex.com/
- 마틴 파울러의 웹사이트의 "제어 역전 컨테이너들과 종속성 주입 패턴" : http://www.martinfowler.com/articles/injection.html
- MSDN 매거진의 "디자인 패턴들 : 종속성 주입" : http://msdn.microsoft.com/en-us/magazine/cc163739.aspx
- MSDN 매거진의 "느슨하게 하기 : 더 유연한 응용프로그램을 위해 당신의 소프트웨어 종속성들을 길들이기" : http://msdn.microsoft.com/en-us/magazine/cc337885.aspx
- 캐슬( Castle ) 프로젝트 : http://structuremap.sourceforge.net/Default.htm
- StructureMap : http://structuremap.sourceforge.net/Default.htm
- Spring.NET : http://www.springframework.net/
'Programming > Prism4.1' 카테고리의 다른 글
진보된 MVVM 시나리오들 (0) | 2014.09.20 |
---|---|
MVVM 패턴 구현하기 (0) | 2014.09.16 |
모듈러 응용프로그램 개발 (0) | 2014.09.13 |
프리즘 응용프로그램 초기화하기 (0) | 2014.08.24 |
왜 프리즘을 사용하는가? (0) | 2014.08.19 |
소개 (0) | 2014.08.18 |
프리즘 4.1 설치 (0) | 2014.08.14 |