문제

저는 제가 진행 중인 애완동물 프로젝트에 캐슬 윈저를 사용하고 있습니다.새 객체를 생성하려면 코드의 여러 위치에서 IoC 컨테이너를 호출해야 한다는 것을 깨닫기 시작했습니다.컨테이너에 대한 이러한 종속성은 내 코드를 유지 관리하기 어렵게 만듭니다.

이 문제를 해결하기 위해 제가 사용한 두 가지 솔루션이 있습니다.

저는 객체를 생성해야 하는 애플리케이션 부분에 삽입할 수 있는 컨테이너 주변의 래퍼로 추상 팩토리를 생성하려고 했습니다.이것은 작동하지만 Castle이 자신의 컨테이너를 종속성으로 주입하는 데 어려움을 겪기 때문에 몇 가지 단점이 있습니다.그래서 저는 그것을 손으로 해야 합니다. 이런 종류의 작업은 IoC 컨테이너의 전체 목적을 무효화합니다.

저는 IoC 컨테이너를 래핑하고 중앙 팩토리/저장소로 작동하기 위해 기본 applicationcontroller 클래스를 사용했습니다.이것은 매우 성공적이었지만 이 클래스는 너무 커지고 중앙 신 개체처럼 작동하며 거의 모든 다른 개체에 대한 참조가 있습니다.

두 솔루션 모두 일종의 작업이지만 둘 다 단점이 있습니다.그래서 다른 사람들도 같은 문제를 겪고 더 나은 해결책을 찾았는지 궁금합니다.


편집하다문제는 객체 B에 의존하는 객체 A에 대한 것이 아닙니다.여기서는 일반적으로 생성자 주입을 사용하고 모든 것이 작동합니다.때로는 수명 동안 다양한 수의 B 유형 개체를 생성해야 하는 A 유형 개체가 있습니다.이 작업을 수행하는 방법을 잘 모르겠습니다.

@블레어 콘래드:현재까지 유지보수 문제는 심각하지 않습니다.일부 클래스는 Container.Resolve<>를 호출하는 컨테이너 개체에 의존했습니다.그리고 나는 인프라라고 생각하는 것에 따라 코드를 갖고 싶지 않습니다.나는 아직 시도 중이어서 이 프로젝트를 위해 ninject에서 castle로 전환할 때 많은 코드를 변경해야 한다는 것을 알았습니다.

@꽃들:흠.나는 당신의 주먹 솔루션을 좋아합니다.제가 시도한 두 가지 솔루션에서 작동하는 기능을 결합한 것입니다.나는 여전히 객체에 대해 너무 많이 생각하고 인터페이스/책임에 대해서는 충분하지 않다고 생각합니다.나는 목적에 맞게 구축된 공장을 시도했지만 배후에서 컨테이너를 사용하여 객체를 생성하게 하고 싶었지만 컨테이너를 깨끗한 방식으로 객체로 DI할 수 있는 방법을 찾지 못했습니다.

도움이 되었습니까?

해결책

적어도 내 애플리케이션에서 종속성 주입의 주요 이점은 상황에 구애받지 않는 코드를 작성할 수 있다는 것입니다.그러한 관점에서 볼 때 두 번째 솔루션은 DI가 제공할 수 있는 이점을 실제로 전복시키는 것처럼 보입니다.'신 객체'가 이를 참조하는 각 클래스에 서로 다른 인터페이스를 노출한다면 그다지 나쁘지 않을 수도 있습니다.하지만 그렇게까지 갔다면 왜 골대까지 끝까지 가져가지 않는지 모르겠습니다.

예:God 객체에는 getFoo() 메소드와 getBar() 메소드가 있습니다.객체 A에는 Foo가 필요하고 객체 B에는 Bar가 필요합니다.A가 Foo 하나만 필요하다면 Foo는 A에 직접 주입되어야 하며 A는 신을 전혀 인식해서는 안 됩니다.그러나 A가 Foos를 계속 생성해야 한다면 A에게 신에 대한 참조를 제공하는 것은 거의 불가피합니다.그러나 하나님에 대한 언급의 유형을 좁힘으로써 하나님을 우회함으로써 입는 피해로부터 자신을 보호할 수 있습니다.God이 FooFactory를 구현하도록 하고 A에 God이 구현한 FooFactory에 대한 참조를 제공하면 여전히 컨텍스트 중립적인 방식으로 A에 코드를 작성할 수 있습니다.이는 코드 재사용 기회를 높이고 God으로의 변경이 예상치 못한 부작용을 일으키지 않을 것이라는 확신을 높여줍니다.예를 들어, God에서 getBar()를 제거할 때 클래스 A가 중단되지 않을 것임을 확신할 수 있습니다.

하지만 ...어쨌든 이러한 모든 인터페이스를 가지려면 컨테이너를 전혀 래핑하는 것보다 특별히 제작된 팩토리 클래스를 작성하고 팩토리를 포함한 모든 객체를 컨테이너 내에 함께 연결하는 것이 더 나을 것입니다.컨테이너는 여전히 팩터리를 구성할 수 있습니다.

다른 팁

IoC.Container.Resolve 또는 ContainerFactory.GetContainer와 같은 정적 클래스를 절대 사용하지 마십시오!

이로 인해 코드가 더 복잡해지고 테스트, 유지 관리, 재사용 및 읽기가 더 어려워집니다.

일반적으로 모든 단일 구성 요소 또는 서비스에는 단 하나의 단일 주입 지점, 즉 생성자(선택적 속성 포함)만 있습니다.그리고 일반적으로 구성 요소나 서비스 클래스는 컨테이너와 같은 존재에 대해 알 수 없습니다.

구성요소가 실제로 내부에 동적 해상도를 가져야 하는 경우(예:이름을 기준으로 예외 처리 정책이나 워크플로를 해결하는 경우) 고려하는 것이 좋습니다. 매우 구체적인 공급자를 통해 IoC 권한을 빌려줍니다.

이에 대한 Nick Blumhardt의 미니 시리즈를 확인해 보는 것이 좋습니다.

http://blogs.msdn.com/nblumhardt/archive/2008/12/27/container-managed-application-design-prelude-where-does-the-container-belong.aspx

"목적에 맞게 구축된 팩토리"의 명확성을 높이 평가하고 직접 사용하기도 하지만 공용 인터페이스(작은 "i")가 새 팩토리 및/또는 새 GetX 메서드에 따라 계속 변경되기 때문에 내 디자인에서는 코드 냄새처럼 느껴집니다. 각 구현마다.제레미 밀러의 글을 읽은 후 이제 IoC 컨테이너 데탕트(Detente)가 시작됩니다., 나는 제네릭을 의심하고 컨테이너 자체를 주입하는 것이 갈 길입니다.

Jeremy의 기사에서 제안한 것과 같은 일종의 IServiceLocator 인터페이스로 Ninject, StructureMap 또는 Windsor를 래핑하겠습니다.그런 다음 원래 제안한 루프에서도 코드의 어느 위치에서나 IServiceLocator를 간단히 반환하는 컨테이너 팩토리를 만드세요.

IServiceLocator container = ContainerFactory.GetContainer(); 
while( keepLooping )
{
    IExample example = container.GetInstance<IExample>();
    keepLooping = example.DoWork();
}

컨테이너 팩토리는 항상 동일한 인스턴스를 반환할 수 있으며 IoC 프레임워크 등을 교체할 수 있습니다.

후속조치로 @플립다우트

서비스 로케이터 유형 패턴을 사용하게 된다면 확인해 보세요. http://www.codeplex.com/CommonServiceLocator.여기에는 도움이 될 수 있는 여러 인기 있는 IoC 프레임워크(windsor, 구조 맵)에 사용할 수 있는 일부 바인딩이 있습니다.

행운을 빌어요.

이 경우 주입되는 강력한 형식의 팩토리를 사용하는 것이 좋습니다.이러한 팩토리는 컨테이너를 래핑할 수 있지만 추가 컨텍스트 전달을 허용하고 추가 처리를 수행할 수 있습니다.예를 들어 OrderFactory의 Create는 상황별 매개변수를 허용할 수 있습니다.

일반 서비스 로케이터에 대한 정적 종속성을 갖는 것은 의도와 컨텍스트를 잃어버리기 때문에 나쁜 생각입니다.IoC가 인스턴스를 구축할 때 큰 그림이 있으므로 프로필, 컨텍스트 등과 같은 다양한 요소를 기반으로 올바른 종속성을 제공할 수 있습니다.

CommonServiceLocator는 이 목적을 위한 것이 아니지만 사용하고 싶은 유혹을 받을 수도 있습니다.CommonServiceLocator의 주요 목적은 IoC 컨테이너 간 규격을 원하는 앱/프레임워크를 위한 것입니다.그러나 를 사용하는 앱은 구성 요소 및 종속 항목의 계층 구조를 구축하기 위해 최적으로 한 번만 로케이터를 호출해야 합니다.다시는 직접 호출하면 안 됩니다.우리가 이를 시행할 수 있는 방법이 있었다면 그렇게 했을 것입니다.인 프리즘(http://www.microsoft.com/compositewpf) 모듈 구축을 위해 IContainerFacade를 도입했습니다.그것은 낮은 수준의 서비스 로케이터입니다.돌이켜보면 아마도 ModuleFactory 같은 것을 생성하고 IContianerFacade를 사용하여 이를 확보한 다음 Facade로 직접 이동하는 대신 모듈을 해결하는 데 사용했어야 했습니다.돌이켜 보면 20/20입니다.레벨이 너무 낮아서 실제로 영향을 미치지는 않습니다.

CSL에서는 네이밍에 혼란을 줄 수 있기 때문에 고민을 많이 했습니다.기술적으로 인터페이스가 DI를 수행하는 데 적합하지 않았기 때문에 결국 우리는 CSL을 선택했습니다.

정말 흔한 문제죠.Windsor가 내장되어 있습니다. 형식화된 공장시설 언급된 단점 없이 공장을 사용하는 이점을 얻을 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top