나는 당신의 요점을 수치 적으로 살펴볼 것이지만, 먼저, 당신이 매우 조심해야 할 것이있다 : 소비자가 어떻게 라이브러리를 사용하는지와 라이브러리가 어떻게 구현되는지를 혼동하지 말라 . 이에 대한 좋은 예는 Entity Framework (좋은 라이브러리로 인용)와 ASP.NET의 MVC입니다. 이 두 가지 모두 예를 들어 리플렉션과 같이 후드 아래에서 끔찍한 일을합니다.이 코드는 일상적인 코드를 통해 확산되면 좋은 디자인으로 간주되지 않습니다.
이 라이브러리는 작동 방식이나 비하인드 스토리에서 "투명" 하지 않습니다 . 그러나 소비자에게 좋은 프로그래밍 원칙을 지원하기 때문에 그다지 해롭지 않습니다 . 따라서 이와 같은 라이브러리에 대해 이야기 할 때마다 라이브러리 소비자는 라이브러리 구현 또는 유지 관리에 대해 걱정하지 않아도됩니다. 라이브러리를 사용하는 코드를 작성하는 데 도움이되는 방법에 대해서만 걱정해야합니다. 이 개념들을 혼동하지 마십시오!
따라서 포인트별로 살펴보십시오.
즉시 우리는 내가 위의 예라고 가정 할 수있는 것에 도달합니다. IOC 컨테이너는 대부분의 종속성을 정적으로 설정한다고 말합니다. 글쎄, 아마도 그들이 어떻게 작동하는지에 대한 일부 구현 세부 사항에는 정적 저장소가 포함됩니다 (Ninject와 같은 객체의 인스턴스를 IKernel
핵심 저장소로 사용하는 경향이 있기는하지만 ). 그러나 이것은 당신의 관심사가 아닙니다!
실제로, IoC 컨테이너는 가난한 사람의 의존성 주입만큼이나 범위가 분명합니다. (IoC 컨테이너를 가난한 사람의 DI와 비교하는 것은 전혀 DI와 비교하지 않는 것이 불공평하고 혼란 스러울 것이기 때문에 계속해서 "가난한 사람의 DI"를 중대하게 사용하지 않을 것입니다.)
가난한 사람의 DI에서는 종속성을 수동으로 인스턴스화 한 다음 필요한 클래스에 주입합니다. 의존성을 구성하는 시점에서 로컬 범위 변수, 클래스 변수, 정적 변수에 저장해야 할 작업을 선택하십시오. 무엇이든 저장하지 마십시오. 동일한 인스턴스를 많은 클래스에 전달하거나 각 클래스마다 새 인스턴스를 작성할 수 있습니다. 도대체 무엇이. 요점은 어떤 일이 일어나고 있는지 확인하기 위해 의존성이 생성되는 응용 프로그램 루트 근처의 지점을 살펴 보는 것입니다.
이제 IoC 컨테이너는 어떻습니까? 글쎄, 당신은 정확히 똑같이! 다시 말하지만, Ninject에 용어로 가고, 당신은 바인딩이 설정되어있는 곳을보고, 찾으 말한다 여부 뭔가 같은 InTransientScope
, InSingletonScope
또는 무엇 이건. 이것이 잠재적으로 더 분명한 경우, 객체에 어떤 일이 발생했는지 추적하는 방법을 살펴 보지 않고 범위를 선언하는 코드가 있기 때문에 (객체는 블록 범위를 지정할 수 있지만 그 시간에 여러 번 사용됩니까?) 예를 들어 차단하거나 한 번만). 따라서 범위를 지시하기 위해 원시 언어 기능이 아닌 IoC 컨테이너의 기능을 사용해야한다는 아이디어에 반함이있을 것입니다. 그러나 IoC 라이브러리를 신뢰할 수있는 한 꼭 필요한 단점은 없습니다! .
나는 아직도 당신이 여기서 무슨 말을하는지 모르겠습니다. IoC 컨테이너는 내부 구현의 일부로 개인 속성을 확인합니까? 왜 그런지 알지 못하지만 다시 그렇게한다면 사용중인 라이브러리가 어떻게 구현되는지 걱정하지 않아도됩니다.
아니면 개인 세터에 주입하는 것과 같은 기능을 노출합니까? 솔직히 나는 이것을 본 적이 없으며 이것이 실제로 공통적 인 기능인지 의심 스럽습니다. 그러나 그것이 있더라도 오용 될 수있는 간단한 도구입니다. IoC 컨테이너가 없어도 개인 속성에 액세스하고 수정하는 리플렉션 코드는 몇 줄에 불과합니다. 거의 수행해서는 안되는 것이지만 .NET이 기능을 노출하는 데 나쁜 것은 아닙니다. 누군가가 도구를 명백하고 심각하게 오용하는 경우 도구가 아닌 사람의 잘못입니다.
여기서 가장 중요한 점은 2와 비슷합니다. 대부분의 경우 IoC 컨테이너는 생성자를 사용합니다! 세터 주입은 특별한 이유로 생성자 주입을 사용할 수없는 매우 특정한 상황에 제공됩니다. 세터 주입을 사용하여 얼마나 많은 종속성이 전달되는지를 커버하는 사람은 누구나 도구를 사용하지 못합니다. 그것은 도구의 결함이 아닙니다.
자, 이것이 순진하게 실수하기 쉽고 실수로 IoC 컨테이너가 권장하는 실수라면 괜찮을 것입니다. 내 수업의 모든 구성원을 공개 한 다음 다른 사람이 원하지 않아야하는 것을 수정할 때 다른 사람을 비난하는 것과 같습니다. 그러나 SRP 위반을 막기 위해 세터 주입을 사용하는 사람은 기본 설계 원칙을 고의로 무시하거나 완전히 무시합니다. IoC 컨테이너에 대한 책임은 불합리합니다.
그건 특히 당신이 가난한 사람의 DI와 마찬가지로 쉽게 할 수있는 일도 있기 때문에 사실 :
var myObject
= new MyTerriblyLargeObject { DependencyA = new Thing(), DependencyB = new Widget(), Dependency C = new Repository(), ... };
따라서 실제로 이러한 걱정은 IoC 컨테이너 사용 여부와 완전히 직교하는 것 같습니다.
수업이 함께 작동하는 방식을 변경하는 것은 OCP를 위반하지 않습니다. 만약 그렇다면, 모든 의존성 역전은 OCP 위반을 장려 할 것이다. 이것이 사실이라면 둘 다 같은 SOLID 약어에 있지 않을 것입니다!
또한 포인트 a)와 b)는 OCP와 관련이 없습니다. OCP와 관련하여 어떻게 대답해야할지 모르겠습니다.
내가 추측 할 수있는 유일한 것은 OCP가 런타임에 변경되지 않는 동작과 관련이 있거나 코드의 종속성 라이프 사이클이 제어되는 위치와 관련이 있다고 생각합니다. 그렇지 않습니다. OCP는 요구 사항이 추가되거나 변경 될 때 기존 코드를 수정할 필요가 없습니다. 그것은 모든 관하여 작성 하지 당신이 이미 작성한 코드 (하지만, 물론, 느슨한 결합은 OCP를 달성의 중요한 부분입니다) 붙어 방법에 대한 코드를.
그리고 마지막으로 한 말 :
그러나 수동으로 할 수 없었던 작업에 대한 해결 방법을 수행하도록 컴파일 된 코드를 변경하는 타사 도구에 동일한 신뢰를 부여 할 수는 없습니다.
그렇습니다 . 방대한 수의 프로젝트에 의존하는 이러한 도구가 다른 타사 라이브러리보다 버그가 많거나 예기치 않은 동작을하기 쉽다고 생각할 이유가 없습니다.
추가
방금 소개 단락에서 일부 주소 지정을 사용할 수 있음을 알았습니다. IoC 컨테이너는 의존성 그래프를 작성하기 위해 복잡하고 중복되기 쉬운 코드를 피하기 위해 "우리가 들어 본 적이없는 비밀 기술을 사용하지 않습니다"라고 말하고 있습니다. 그리고 여러분이 옳습니다. 그들이하는 일은 실제로 우리 프로그래머들이하는 것과 같은 기본 기술로 이러한 것들을 다루는 것입니다.
가상 시나리오를 통해 말씀 드리겠습니다. 프로그래머는 큰 응용 프로그램을 만들고 객체 그래프를 작성하는 진입 점에 코드가 매우 지저분하다는 것을 알 수 있습니다. 몇 번이고 반복해서 사용되는 클래스가 있으며 그중 하나를 작성할 때마다 전체 종속성 체인을 다시 작성해야합니다. 또한 각각의 사용자 정의 코드를 제외하고 종속성의 수명주기를 선언하거나 제어하는 표현 방법이 없습니다. 코드가 구조화되지 않았으며 반복으로 가득합니다. 이것은 당신이 소개 단락에서 이야기하는 혼란입니다.
따라서 먼저 반복되는 코드가 구조화되어 비트를 리팩터링하기 시작합니다. 그러나 여러분은 이것이 일반적인 의미로 해결할 수있는 문제라고 생각 합니다.이 특정 프로젝트에만 국한되지는 않지만 앞으로의 모든 프로젝트에서 당신을 도울 수있는 문제입니까?
그래서 당신은 앉아서 그것에 대해 생각하고 의존성을 해결할 수있는 수업이 있어야한다고 결정합니다. 그리고 필요한 공용 메소드를 스케치하십시오.
void Bind(Type interfaceType, Type concreteType, bool singleton);
T Resolve<T>();
Bind
"유형의 생성자 인수가 interfaceType
있는 경우 인스턴스를 전달 하십시오"라고 말합니다 concreteType
. 추가 singleton
매개 변수는 concreteType
매번 같은 인스턴스를 사용할지 또는 항상 새 인스턴스를 만들지 여부를 나타 냅니다.
Resolve
T
인수가 이전에 바인드 된 모든 유형의 인수를 찾을 수있는 생성자 로 구성하려고합니다 . 또한 의존성을 완전히 해결하기 위해 재귀 적으로 호출 할 수도 있습니다. 모든 것이 바인딩되어 있지 않기 때문에 인스턴스를 해결할 수 없으면 예외가 발생합니다.
이것을 직접 구현해 볼 수 있으며 약간의 성찰이 필요하며 바인딩에 대한 일부 캐싱 singleton
이 사실이지만 분명하거나 끔찍한 것은 없습니다. 그리고 당신은 done-하고 한 번 봐라 , 당신은 당신의 자신의 IoC 컨테이너의 핵심이있다! 정말 무서운가요? 이것과 Ninject 또는 StructureMap 또는 Castle Windsor 또는 당신이 선호하는 것의 유일한 차이점은이 기본 버전으로는 충분하지 않은 (많은!) 사용 사례를 다루는 훨씬 더 많은 기능을 가지고 있다는 것입니다. 그러나 그 핵심에는 IoC 컨테이너의 본질이 있습니다.
IOC
와는Explicitness of code
정확히 내가 문제가있는 것입니다. 수동 DI는 쉽게 집안일이 될 수 있지만, 최소한 "자신이 볼 수있는 것을 얻을 수 있습니다." IOC 컨테이너의 바인딩과 선언은 쉽게 숨겨진 병렬 프로그램이 될 수 있습니다.