IOC 컨테이너, OOP 원칙 위반


51

IOC 컨테이너의 목적은 무엇입니까? 그 이유를 다음과 같이 단순화 할 수 있습니다.

OOP / SOLID 개발 원칙을 사용하면 Dependency Injection이 복잡해집니다. 여러 레벨에 대한 종속성을 관리하고 구성을 통해 종속성을 재귀 적으로 전달하는 최상위 진입 점이 있거나 필요에 따라 종속성을 빌드하는 팩토리 / 빌더 패턴 및 인터페이스에 다소 중복 된 코드가 있습니다.

이 작업을 수행 할 OOP / SOLID 방법은 없습니다 슈퍼 꽤 코드를 가지고가.

위의 진술이 사실이라면 IOC 컨테이너는 어떻게합니까? 내가 아는 한, 수동 DI로는 수행 할 수없는 알려지지 않은 기술을 사용하지 않습니다. 따라서 유일한 설명은 IOC 컨테이너가 정적 개체 전용 접근자를 사용하여 OOP / SOLID 원칙을 위반한다는 것입니다.

IOC 컨테이너는 다음과 같은 원칙을 뒷받침합니까? 이것은 내가 잘 이해하고 있지만 다른 사람이 더 잘 이해하고 있다고 느끼기 때문에 실제 질문입니다.

  1. 범위 제어 . 범위는 코드 디자인에 대해 거의 모든 결정을 내리는 이유입니다. 블록, 로컬, 모듈, 정적 / 글로벌. 범위는 블록 수준에서 최대한 정적 수준에서 최대한 명확해야합니다. 선언, 인스턴스화 및 수명주기 종료가 표시되어야합니다. 나는 명시 적 인 한 언어와 GC를 사용하여 범위를 관리합니다. 필자의 연구에서 IOC 컨테이너는 대부분 또는 모든 종속성을 정적으로 설정하고 뒤에서 AOP 구현을 통해 제어합니다. 투명한 것은 없습니다.
  2. 캡슐화 . 캡슐화의 목적은 무엇입니까? 왜 비공개 회원을 유지해야합니까? 실질적인 이유로 API의 구현자는 상태를 변경하여 구현을 중단 할 수 없습니다 (소유자 클래스에서 관리해야 함). 또한 보안상의 이유로 회원국을 추월하고 검증 및 등급 관리를 우회하는 주입이 불가능합니다. 따라서 컴파일 시간 전에 코드를 삽입하여 개인 구성원에 대한 외부 액세스를 허용하는 모든 것 (모의 프레임 워크 또는 IOC 프레임 워크)은 매우 방대합니다.
  3. 단일 책임 원칙 . 표면적으로 IOC 컨테이너는 물건을 더 깨끗하게 만드는 것 같습니다. 그러나 도우미 프레임 워크없이 어떻게 같은 일을 수행 할 수 있을지 상상해보십시오. 수십 개의 의존성이 전달되는 생성자가있을 것입니다. 즉, IOC 컨테이너로 덮어 쓰는 것은 아닙니다. 좋은 일입니다! 코드를 리팩터링하고 SRP를 따르라는 표시입니다.
  4. 휴일 / 열기 . SRP가 클래스 전용이 아닌 것처럼 (SRP를 메서드뿐만 아니라 단일 책임 라인에 적용). Open / Closed는 클래스 코드를 변경하지 않는 고급 이론이 아닙니다. 프로그램 구성을 이해하고 변경되는 내용과 확장되는 내용을 제어하는 ​​방법입니다. IOC 컨테이너는 다음과 같은 이유로 클래스가 부분적으로 작동하는 방식을 변경할 수 있습니다.

    • 에이. 기본 코드는 종속성을 전환하지 않고 프레임 워크 구성을 결정합니다.

    • 비. 범위는 호출 멤버에 의해 제어되지 않는 시간에 변경 될 수 있으며 대신 정적 프레임 워크에 의해 외부 적으로 결정됩니다.

따라서 클래스의 구성은 실제로 닫히지 않고 타사 도구의 구성에 따라 변경됩니다.

이것이 문제인 이유는 모든 IOC 컨테이너의 마스터 일 필요는 없기 때문입니다. 그리고 IOC 컨테이너에 대한 아이디어는 훌륭하지만 구현이 좋지 않은 외관을 나타내는 것 같습니다. 그러나 외부 스코프 제어, 개인 멤버 액세스 및 지연로드를 달성하려면 사소한 의심스러운 일이 많이 발생합니다. AOP는 훌륭하지만 IOC 컨테이너를 통해 달성되는 방식도 의문의 여지가 있습니다.

C #과 .NET GC가 내가 기대하는 것을 할 수 있다고 믿을 수 있습니다. 그러나 수동으로 할 수 없었던 작업에 대한 해결 방법을 수행하도록 컴파일 된 코드를 변경하는 타사 도구에 동일한 신뢰를 부여 할 수는 없습니다.

EG : Entity Framework 및 기타 ORM은 강력한 형식의 개체를 만들어 데이터베이스 개체에 매핑 할뿐만 아니라 CRUD를 수행하기위한 보일러 플레이트 기본 기능을 제공합니다. 누구나 자신의 ORM을 구축하고 OOP / SOLID 원칙을 계속 수동으로 따를 수 있습니다. 그러나 이러한 프레임 워크가 도움이되므로 매번 휠을 다시 발명 할 필요가 없습니다. IOC 컨테이너는 OOP / SOLID 원칙을 고의로 해결하고 덮어 쓰는 데 도움이되는 것 같습니다.


13
사이 한 상관 관계 IOC와는 Explicitness of code정확히 내가 문제가있는 것입니다. 수동 DI는 쉽게 집안일이 될 수 있지만, 최소한 "자신이 볼 수있는 것을 얻을 수 있습니다." IOC 컨테이너의 바인딩과 선언은 쉽게 숨겨진 병렬 프로그램이 될 수 있습니다.
Eugene Podskal

6
이것은 어떻게 질문입니까?
Stephen

8
이것은 질문보다 블로그 게시물처럼 보입니다.
Bart van Ingen Schenau

4
나는 "너무 논증 적"인 질문에 대한 내부 범주를 가지고 있는데, 이는 공식적인 가까운 이유는 아니지만 때로는 "실질적인 질문이 아닌"결론을 내리기 위해 투표를한다. 그러나 두 가지 측면이 있으며이 질문은 첫 번째 질문에만 해당됩니다. (1) 질문은 논문을 제시하고 정확한지 묻습니다. (2) 질문자는 동의하지 않는 답변에 대해 초기 입장을 방어합니다. Matthew의 답변은 질문의 내용 중 일부와 모순되므로, 질문자가 크롤링하지 않는 한 개인적으로이 질문을 "신정 한 질문입니다.
Steve Jessop

3
@BenAaronson 벤 감사합니다. 연구를 통해 배운 내용을 전달하고 IOC 컨테이너의 특성에 대한 답변을 얻으려고합니다. 내 연구의 결과로 나는이 원칙들이 깨지는 것을 발견했다. 내 질문에 대한 가장 좋은 대답은 IOC 컨테이너가 OOP / SOLID 원칙을 위반하지 않고 수동으로 할 수없는 일을 할 수 있음을 확인하거나 거부하는 것입니다. 귀하의 큰 의견으로 인해 더 많은 예를 들어 제 질문을 리팩토링했습니다.
Suamere

답변:


35

나는 당신의 요점을 수치 적으로 살펴볼 것이지만, 먼저, 당신이 매우 조심해야 할 것이있다 : 소비자가 어떻게 라이브러리를 사용하는지와 라이브러리가 어떻게 구현되는지를 혼동하지 말라 . 이에 대한 좋은 예는 Entity Framework (좋은 라이브러리로 인용)와 ASP.NET의 MVC입니다. 이 두 가지 모두 예를 들어 리플렉션과 같이 후드 아래에서 끔찍한 일을합니다.이 코드는 일상적인 코드를 통해 확산되면 좋은 디자인으로 간주되지 않습니다.

이 라이브러리는 작동 방식이나 비하인드 스토리에서 "투명" 하지 않습니다 . 그러나 소비자에게 좋은 프로그래밍 원칙을 지원하기 때문에 그다지 해롭지 않습니다 . 따라서 이와 같은 라이브러리에 대해 이야기 할 때마다 라이브러리 소비자는 라이브러리 구현 또는 유지 관리에 대해 걱정하지 않아도됩니다. 라이브러리를 사용하는 코드를 작성하는 데 도움이되는 방법에 대해서만 걱정해야합니다. 이 개념들을 혼동하지 마십시오!

따라서 포인트별로 살펴보십시오.

  1. 즉시 우리는 내가 위의 예라고 가정 할 수있는 것에 도달합니다. IOC 컨테이너는 대부분의 종속성을 정적으로 설정한다고 말합니다. 글쎄, 아마도 그들이 어떻게 작동하는지에 대한 일부 구현 세부 사항에는 정적 저장소가 포함됩니다 (Ninject와 같은 객체의 인스턴스를 IKernel핵심 저장소로 사용하는 경향이 있기는하지만 ). 그러나 이것은 당신의 관심사가 아닙니다!

    실제로, IoC 컨테이너는 가난한 사람의 의존성 주입만큼이나 범위가 분명합니다. (IoC 컨테이너를 가난한 사람의 DI와 비교하는 것은 전혀 DI와 비교하지 않는 것이 불공평하고 혼란 스러울 것이기 때문에 계속해서 "가난한 사람의 DI"를 중대하게 사용하지 않을 것입니다.)

    가난한 사람의 DI에서는 종속성을 수동으로 인스턴스화 한 다음 필요한 클래스에 주입합니다. 의존성을 구성하는 시점에서 로컬 범위 변수, 클래스 변수, 정적 변수에 저장해야 할 작업을 선택하십시오. 무엇이든 저장하지 마십시오. 동일한 인스턴스를 많은 클래스에 전달하거나 각 클래스마다 새 인스턴스를 작성할 수 있습니다. 도대체 무엇이. 요점은 어떤 일이 일어나고 있는지 확인하기 위해 의존성이 생성되는 응용 프로그램 루트 근처의 지점을 살펴 보는 것입니다.

    이제 IoC 컨테이너는 어떻습니까? 글쎄, 당신은 정확히 똑같이! 다시 말하지만, Ninject에 용어로 가고, 당신은 바인딩이 설정되어있는 곳을보고, 찾으 말한다 여부 뭔가 같은 InTransientScope, InSingletonScope또는 무엇 이건. 이것이 잠재적으로 더 분명한 경우, 객체에 어떤 일이 발생했는지 추적하는 방법을 살펴 보지 않고 범위를 선언하는 코드가 있기 때문에 (객체는 블록 범위를 지정할 수 있지만 그 시간에 여러 번 사용됩니까?) 예를 들어 차단하거나 한 번만). 따라서 범위를 지시하기 위해 원시 언어 기능이 아닌 IoC 컨테이너의 기능을 사용해야한다는 아이디어에 반함이있을 것입니다. 그러나 IoC 라이브러리를 신뢰할 수있는 한 꼭 필요한 단점은 없습니다! .

  2. 나는 아직도 당신이 여기서 무슨 말을하는지 모르겠습니다. IoC 컨테이너는 내부 구현의 일부로 개인 속성을 확인합니까? 왜 그런지 알지 못하지만 다시 그렇게한다면 사용중인 라이브러리가 어떻게 구현되는지 걱정하지 않아도됩니다.

    아니면 개인 세터에 주입하는 것과 같은 기능을 노출합니까? 솔직히 나는 이것을 본 적이 없으며 이것이 실제로 공통적 인 기능인지 의심 스럽습니다. 그러나 그것이 있더라도 오용 될 수있는 간단한 도구입니다. IoC 컨테이너가 없어도 개인 속성에 액세스하고 수정하는 리플렉션 코드는 몇 줄에 불과합니다. 거의 수행해서는 안되는 것이지만 .NET이 기능을 노출하는 데 나쁜 것은 아닙니다. 누군가가 도구를 명백하고 심각하게 오용하는 경우 도구가 아닌 사람의 잘못입니다.

  3. 여기서 가장 중요한 점은 2와 비슷합니다. 대부분의 경우 IoC 컨테이너는 생성자를 사용합니다! 세터 주입은 특별한 이유로 생성자 주입을 사용할 수없는 매우 특정한 상황에 제공됩니다. 세터 주입을 사용하여 얼마나 많은 종속성이 전달되는지를 커버하는 사람은 누구나 도구를 사용하지 못합니다. 그것은 도구의 결함이 아닙니다.

    자, 이것이 순진하게 실수하기 쉽고 실수로 IoC 컨테이너가 권장하는 실수라면 괜찮을 것입니다. 내 수업의 모든 구성원을 공개 한 다음 다른 사람이 원하지 않아야하는 것을 수정할 때 다른 사람을 비난하는 것과 같습니다. 그러나 SRP 위반을 막기 위해 세터 주입을 사용하는 사람은 기본 설계 원칙을 고의로 무시하거나 완전히 무시합니다. IoC 컨테이너에 대한 책임은 불합리합니다.

    그건 특히 당신이 가난한 사람의 DI와 마찬가지로 쉽게 할 수있는 일도 있기 때문에 사실 :

    var myObject 
       = new MyTerriblyLargeObject { DependencyA = new Thing(), DependencyB = new Widget(), Dependency C = new Repository(), ... };
    

    따라서 실제로 이러한 걱정은 IoC 컨테이너 사용 여부와 완전히 직교하는 것 같습니다.

  4. 수업이 함께 작동하는 방식을 변경하는 것은 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매번 같은 인스턴스를 사용할지 또는 항상 새 인스턴스를 만들지 여부를 나타 냅니다.

ResolveT인수가 이전에 바인드 된 모든 유형의 인수를 찾을 수있는 생성자 로 구성하려고합니다 . 또한 의존성을 완전히 해결하기 위해 재귀 적으로 호출 할 수도 있습니다. 모든 것이 바인딩되어 있지 않기 때문에 인스턴스를 해결할 수 없으면 예외가 발생합니다.

이것을 직접 구현해 볼 수 있으며 약간의 성찰이 필요하며 바인딩에 대한 일부 캐싱 singleton이 사실이지만 분명하거나 끔찍한 것은 없습니다. 그리고 당신은 done-하고 한 번 봐라 , 당신은 당신의 자신의 IoC 컨테이너의 핵심이있다! 정말 무서운가요? 이것과 Ninject 또는 StructureMap 또는 Castle Windsor 또는 당신이 선호하는 것의 유일한 차이점은이 기본 버전으로는 충분하지 않은 (많은!) 사용 사례를 다루는 훨씬 더 많은 기능을 가지고 있다는 것입니다. 그러나 그 핵심에는 IoC 컨테이너의 본질이 있습니다.


고마워 벤. 나는 솔직히 IOC 컨테이너로 약 1 년 동안 일했지만, 그렇게하지는 않지만 자습서와 동료는 실제로 부동산 주입 (개인 포함)에 중점을 둡니다. 그것은 미쳤다. 그리고 그것은 내가하는 모든 포인트를 가져온다. 그러나 다른 사람들 이이 상황에 처하더라도 IOC 컨테이너가 원리를 따르기 위해 어떻게 작동 해야하는지에 대한 자세한 내용을 배우고 코드 검토에서 이러한 원칙을 깨우는 것이 최선이라고 생각합니다. 그러나 ... (계속)
Suamere

저의 가장 큰 관심사는 반드시 OOP / SOLID 원칙에 수록된 것은 아니며 범위의 명확성입니다. 나는 여전히 키워드의 창을 이해하는 블록, 로컬, 모듈 및 글로벌 레벨 범위를 던지고 있습니다. 블록을 사용하고 무언가가 범위를 벗어나거나 배치되는 시점을 결정하는 선언에 대한 전체 아이디어는 나에게 큰 영향을 미치며, 나는 이것이 매우 기본적인 개발 부분을 확장 키워드로 대체하기 위해 IOC 컨테이너의 가장 무서운 부분이라고 생각합니다. .
Suamere

따라서 귀하의 답변이 실제로 이것의 핵심을 다루기 때문에 답변으로 표시했습니다. 그리고 내가 읽는 방식은 다른 사람들이하는 것처럼 IOC 컨테이너가 커버 아래에서하는 일을 믿어야한다는 것입니다. 그리고 오용 가능성과 그것을 다루는 우아한 방법이있는 한, 그것은 상점과 코드 리뷰가 걱정하고 좋은 개발 원칙을 따르기 위해 실사를해야합니다.
Suamere

2
4와 관련하여 Dependency Injection은 SOLID 약어에 없습니다 . 'D'= ​​'종속성 역전 원리 (Dependency Inversion Principle)'는 완전히 무관 한 개념입니다.
astreltsov

@astr 좋은 지적. 내가 처음부터 쓰려고했던 것 같아서 "injection"을 "inversion"으로 바꿨습니다. 의존성 반전이 반드시 여러 가지 구체적인 구현을 의미하지는 않지만 그 의미가 충분히 명확하다고 생각하기 때문에 여전히 약간 단순화되었습니다 . 구현을 전환하는 것이 OCP 위반 인 경우 다형성 추상화에 의존하는 것은 위험합니다.
벤 애런

27

IOC 컨테이너가 이러한 원칙을 많이 위반하지 않습니까?

이론에 의하면? 아니요. IoC 컨테이너는 도구 일뿐입니다. 단일 책임이 있고, 분리 된 인터페이스를 가지고 있고, 일단 작성된 동작을 수정할 수없는 객체 등을 가질 수 있습니다.

실제로? 물론.

필자는 소수의 프로그래머가 IoC 컨테이너 를 사용하여 시스템의 동작을 변경하기 위해 일부 구성을 사용하여 개방 / 폐쇄 원칙을 위반 한다고 구체적 으로 언급한다고 들었습니다 . 작업의 90 %가 스프링 구성을 수정했기 때문에 XML 코딩에 대한 농담이있었습니다. 그리고 모든 IoC 컨테이너가 아닌 종속성을 숨기는 것이 매우 결합되고 취약한 코드를 만드는 빠르고 쉬운 방법이라는 것은 확실합니다.

다른 방식으로 살펴 보겠습니다. 하나의 기본 의존성을 가진 매우 기본적인 클래스를 생각해 봅시다. Action매개 변수를 사용하지 않고 반환하는 대리자 또는 functor 에 따라 다릅니다 void. 이 수업의 책임은 무엇입니까? 당신은 말할 수 없습니다. 나는 그 의존성을 CleanUpAction당신이 원하는 일을한다고 생각 하게하는 것과 같은 명확한 이름을 지을 수 있습니다. IoC가 작동하자마자 무엇이든 됩니다. 누구나 구성에 들어가서 거의 임의의 작업을 수행하도록 소프트웨어를 수정할 수 있습니다.

"그것은 Action생성자로 전달하는 것과 어떻게 다릅니 까?" 물어. 소프트웨어가 배포 된 후 (또는 런타임에) 생성자로 전달되는 내용을 변경할 수 없기 때문에 다릅니다. 단위 테스트 (또는 소비자 단위 테스트)가 대리자가 생성자에 전달되는 시나리오를 다루었 기 때문에 다릅니다.

"그러나 그것은 가짜 예제입니다! 제 물건은 행동을 바꾸는 것을 허용하지 않습니다!" 당신은 외쳤다. 말해 주셔서 죄송합니다. 주입하는 인터페이스가 단지 데이터 가 아닌 한 . 인터페이스는 단순한 데이터가 아닙니다. 단순한 데이터 인 경우 간단한 객체를 만들고 사용하기 때문입니다. 인젝션 포인트에서 가상 메소드를 사용하자마자 IoC를 사용하는 클래스 계약은 "나는 무엇이든 할 수 있습니다 "입니다.

"스크립팅을 사용하여 작업을 수행하는 것과 다른 점은 무엇입니까?" 여러분 중 일부는 묻습니다. 다르지 않습니다. 프로그램 디자인 관점에서 차이는 없습니다. 임의의 코드를 실행하기 위해 프로그램을 호출하고 있습니다. 물론, 그것은 오랜 세월 동안 게임에서 이루어졌습니다. 수많은 시스템 관리 도구에서 수행됩니다. OOP입니까? 실제로는 아닙니다.

현재 유비쿼터스에 대한 변명의 여지가 없습니다. IoC 컨테이너는 하나의 확실한 목적을 가지고 있습니다. 종속성이 너무 많을 때 종속성을 서로 붙이거나 너무 빠르게 이동하여 이러한 종속성을 명시 적으로 표현하는 것은 비현실적입니다. 실제로이 시나리오에 적합한 기업은 거의 없습니다.


3
권리. 그리고 많은 상점들은 그들의 제품이 너무 복잡해서 그들이 실제로는 그렇지 않을 때 그 범주에 속한다고 주장 할 것입니다. 많은 시나리오의 진실도 마찬가지입니다.
Suamere

12
그러나 IoC는 당신이 말한 것과 정반대입니다. 프로그램의 열기 / 닫기를 사용합니다. 코드 자체를 변경하지 않고도 전체 프로그램의 동작을 변경할 수 있습니다.
Euphoric

6
@Euphoric-확장을 위해 열리고 수정을 위해 닫습니다. 전체 프로그램의 동작을 변경할 수 있다면 수정을 위해 닫히지 않은 것입니까? IoC 구성은 여전히 ​​소프트웨어이며, Java 또는 C # 또는 XML이 아닌 XML 형식이라도 클래스에서 작동하는 코드입니다.
Telastyn

4
@Telastyn "수정을 위해 닫힘"은 전체의 동작을 변경하기 위해 코드를 변경 (수정) 할 필요가 없음을 의미합니다. 외부 구성을 사용하면 새 dll을 가리키고 전체 변경 동작을 수행 할 수 있습니다.
행복감

12
@Telastyn 그것은 개방 / 폐쇄 원칙이 말하는 것이 아닙니다. 그렇지 않으면 매개 변수를 사용하는 메서드는 다른 매개 변수를 전달하여 동작을 "수정"할 수 있으므로 OCP를 위반합니다. 마찬가지로 OCP 버전에서도 DI와 직접 충돌 할 수 있으므로 SOLID 약어에 모두 나타나는 것이 다소 이상합니다.
Ben Aaronson

14

IoC 컨테이너 사용이 반드시 OOP / SOLID 원칙을 위반합니까? 없음 .

OoP / SOLID 원칙을 위반하는 방식으로 IoC 컨테이너를 사용할 수 있습니까? .

IoC 컨테이너는 애플리케이션에서 종속성을 관리하기위한 프레임 워크 일뿐입니다.

당신은 게으른 주입, 속성 설정 기, 그리고 아직 사용할 필요가 없다고 생각한 몇 가지 다른 기능을 언급했습니다. 그러나 이러한 특정 기능의 사용은 IoC 컨테이너를 구현하는 기술의 한계로 인한 것입니다.

예를 들어 ASP.NET WebForms의 경우 인스턴스를 생성 할 수 없으므로 속성 삽입을 사용해야합니다 Page. WebForms는 엄격한 OOP 패러다임을 염두에두고 설계되지 않았기 때문에 이해할 수 있습니다.

반면에 ASP.NET MVC는 OOP / SOLID 친화적 인 생성자 주입을 사용하여 IoC 컨테이너를 사용할 수 있습니다.

이 시나리오 (생성자 주입 사용)에서는 다음과 같은 이유로 SOLID 원칙을 홍보한다고 생각합니다.

  • 단일 책임 원칙-더 작은 클래스가 많으면 이러한 클래스가 매우 구체적이며 기존에 한 가지 이유가 있습니다. IoC 컨테이너를 사용하면 훨씬 쉽게 구성 할 수 있습니다.

  • Open / Closed-IoC 컨테이너 사용이 실제로 빛을 발하는 곳에서 다양한 종속성을 주입하여 클래스의 기능을 확장 할 수 있습니다. 의존성을 주입하면 해당 클래스의 동작을 수정할 수 있습니다. 좋은 예는 캐싱 또는 로깅 추가를 위해 데코레이터를 작성하여 주입하는 클래스를 변경하는 것입니다. 적절한 추상화 수준으로 작성된 경우 종속성 구현을 완전히 변경할 수 있습니다.

  • Liskov 대체 원칙-실제로는 관련이 없음

  • 인터페이스 분리 원리-원하는 경우 단일 콘크리트 시간에 여러 인터페이스를 할당 할 수 있습니다. 소금 한 알의 가치가있는 IoC 컨테이너는이를 쉽게 수행 할 수 있습니다.

  • 종속성 반전-IoC 컨테이너를 사용하면 종속성 반전을 쉽게 수행 할 수 있습니다.

당신은 많은 의존성을 정의하고 관계와 범위를 선언하고 빙뱅 붐을 일으킨다 : 어떤 시점에서 코드 나 IL을 바꾸어 작동시키는 마술 같은 추가 기능이있다. 그것은 명백하거나 투명하지 않습니다.

명시적이고 투명합니다. IoC 컨테이너에 종속성을 연결하는 방법과 객체 수명을 관리하는 방법을 알려 주어야합니다. 이것은 컨벤션, 구성 파일 또는 시스템의 기본 응용 프로그램에서 작성된 코드에 의해 수행 될 수 있습니다.

IOC 컨테이너를 사용하여 코드를 쓰거나 읽을 때 약간 우아하지 않은 코드가 제거된다는 데 동의합니다.

이것이 OOP / SOLID가 시스템을 관리하기 쉽게 만드는 이유입니다. IoC 컨테이너 사용은 해당 목표와 일치합니다.

그 클래스의 작가는 "우리가 IOC 컨테이너를 사용하지 않으면 생성자는 12 개의 매개 변수를 가질 것이다! 끔찍하다!"

12 개의 종속성을 가진 클래스는 사용하는 컨텍스트에 관계없이 SRP 위반 일 수 있습니다.


2
훌륭한 답변입니다. 또한 모든 주요 IOC 컨테이너도 AOP를 지원하므로 OCP에 많은 도움이 될 수 있습니다. 교차 절단 문제의 경우 AOP는 일반적으로 Decorator보다 OCP 친화적 인 경로입니다.
Ben Aaronson

2
@ BenAaronson AOP가 클래스에 코드를 삽입한다는 점을 고려할 때 더 OCP 친화적이라고 부르지는 않습니다. 컴파일 / 런타임에 클래스를 강제로 열고 변경하고 있습니다.
Doval

1
@ Doval 클래스에 코드를 주입하는 방법을 모르겠습니다. 참고 나는 IL 직조 스타일이 아닌 인터셉터가있는 Castle DynamicProxy 스타일에 대해 이야기하고 있습니다. 그러나 인터셉터는 본질적으로 특정 리플렉션을 사용하여 특정 인터페이스에 연결하지 않아도되는 데코레이터입니다.
Ben Aaronson

"종속성 반전-IoC 컨테이너를 사용하면 종속성 반전을 쉽게 수행 할 수 있습니다." 다른 원칙과 동일합니다.
Den

나는 사실에 근거하여 어떤 것이 나쁘지 않다는 설명의 논리를 얻지 못합니다. ServiceLocator도 프레임 워크로 만들어지며 나쁜 것으로 간주됩니다.)
ipavlu

5

IOC 컨테이너가 많은 OOP / SOLID 원칙을 깨뜨리고 코더가 깨지는 것을 허용하지 않습니까?

staticC # 의 키워드를 사용하면 개발자가 많은 OOP / SOLID 원칙을 깨뜨릴 수 있지만 올바른 상황에서 여전히 유효한 도구입니다.

IoC 컨테이너는 잘 구조화 된 코드를 허용하고 개발자의인지 부담을 줄입니다. IoC 컨테이너를 사용하면 SOLID 원칙을 훨씬 쉽게 따를 수 있습니다. 오용 될 수 있지만, 오용 될 수있는 도구의 사용을 배제하면 프로그래밍을 모두 포기해야합니다.

따라서이 욕설은 잘못 작성된 코드에 대한 몇 가지 유효한 요점을 제기하지만 정확히 질문이 아니며 정확하게 유용하지는 않습니다.


IOC 컨테이너에 대한 이해는 범위, 게으름 및 접근성을 관리하기 위해 컴파일 된 코드를 변경하여 OOP / SOLID를 손상시키는 작업을 수행하지만 해당 프레임 워크에서 해당 구현을 숨 깁니다. 그러나 예, 잘못 사용하기 위해 다른 문을 추가로 엽니 다. 내 질문에 대한 가장 좋은 대답은 내 연구에서 추가하거나 부정하는 IOC 컨테이너가 구현되는 방법에 대한 설명입니다.
Suamere

2
@ Suamere-IOC의 정의를 너무 광범위하게 사용하고 있다고 생각합니다. 내가 사용하는 것은 컴파일 된 코드를 수정하지 않습니다. 컴파일 된 코드를 수정하는 다른 비 IOC 도구가 많이 있습니다. 어쩌면 당신의 제목은 "컴파일 된 코드를 수정 하는가 ..."와 비슷할 것입니다.
Cerad

@Suamere IoC에 익숙하지는 않지만 IoC가 컴파일 된 코드를 변경하는 것에 대해 들어 본 적이 없습니다. 어떤 플랫폼 / 언어 / 프레임 워크에 대한 정보를 제공 하시겠습니까?
행복감

1
"IoC 컨테이너는 SOLID 원칙을 훨씬 쉽게 따르는 데 사용될 수 있습니다." -좀 더 자세히 설명해 주시겠습니까? 그것이 각 원칙에 얼마나 구체적으로 도움이되는지 설명하면 도움이 될 것입니다. 물론 무언가를 활용하는 것은 무언가를 돕는 것과 같은 것이 아닙니다 (예 : DI).
Den

1
@Euphoric 나는 suamere가 이야기하고있는 .net 프레임 워크에 대해 알지 못하지만 Spring은 확실히 코드가 수정되지 않습니다. 가장 확실한 예는 메소드 기반 인젝션 ​​지원 (클래스에서 추상 메소드를 대체하여 관리하는 종속성을 리턴 함)입니다. 또한 코드를 래핑하여 추가 동작 (예 : 트랜잭션 자동 관리)을 제공하기 위해 자동 생성 프록시를 광범위하게 사용합니다. 그러나이 중 많은 부분이 실제로 DI 프레임 워크로서의 역할과 관련이 없습니다.
Jules

3

귀하의 질문에 여러 가지 실수와 오해가 있습니다. 첫 번째 주요 사항은 속성 / 필드 주입, 생성자 주입 및 서비스 로케이터 사이에 차이가 없다는 것입니다. 일을하는 올바른 방법에 대해 많은 토론 (예 : 불꽃 전쟁)이있었습니다. 귀하의 질문에, 당신은 속성 주입 만 가정하고 생성자 주입을 무시하는 것 같습니다.

두 번째는 IoC 컨테이너가 어떻게 코드 디자인에 영향을 준다고 가정한다는 것입니다. IoC를 사용하는 경우 코드 디자인을 변경하지 않아도되거나 최소한 디자인 할 필요는 없습니다. 많은 생성자가있는 클래스의 문제는 코드에 실제 문제를 숨기는 IoC의 경우이며 (SRP를 깰 수있는 클래스) 숨겨진 종속성은 사람들이 속성 삽입 및 서비스 로케이터의 사용을 권장하지 않는 이유 중 하나입니다.

공개 폐쇄 원칙의 문제가 어디에서 발생하는지 이해하지 못하므로 이에 대해서는 언급하지 않습니다. 그러나 SOLID의 한 부분이 누락되어 이에 영향을줍니다. 종속성 반전 원칙. DIP를 따르면 종속성을 반전 시키면 추상화가 발생하고 클래스의 인스턴스가 작성 될 때 구현을 해결해야 함을 알 수 있습니다. 이 방법을 사용하면 많은 클래스가 생겨 구성이 제대로 작동하기 위해 여러 인터페이스를 구현하고 제공해야합니다. 그런 다음 이러한 종속성을 수동으로 제공하려면 추가 작업을 많이 수행해야합니다. IoC 컨테이너를 사용하면이 작업을보다 쉽게 ​​수행 할 수 있으며 프로그램을 다시 컴파일하지 않고도 변경할 수 있습니다.

따라서 귀하의 질문에 대한 대답은 아니오입니다. IoC 컨테이너는 OOP 설계 원칙을 위반하지 않습니다. 반대로, 그들은 SOLID 원칙 (특히 Dependency-Inversion 원칙)에 따라 발생하는 문제를 해결합니다.


최근에 사소한 프로젝트에 IoC (Autofac)를 적용하려고했습니다. 나는 언어가 아닌 구문 (new () vs API)으로 비슷한 작업을 수행해야한다는 것을 깨달았습니다. 인터페이스로 해결해야 할 것과 구체적인 클래스로 해결 해야하는 것을 지정하고 인스턴스와 싱글 톤을 지정해야합니다. 속성 주입이 순환 종속성을 완화시키는 데 효과적입니다. 포기하기로 결정했습니다. ASP MVC의 컨트롤러와 잘 작동합니다.
Den

@Den 프로젝트는 분명히 의존성 역전을 염두에두고 설계되지 않았습니다. 그리고 나는 IoC를 사용하는 것이 사소한 것이라고 말하지 않았습니다.
Euphoric

실제로, 그 일은-처음부터 Dependency Inversion을 사용하고 있습니다. 그 이상으로 디자인에 영향을 미치는 IoC가 가장 큰 걱정입니다. 예를 들어 IoC를 더 단순하게 만들기 위해 왜 어디서나 인터페이스를 사용해야합니까? 또한 질문에 대한 주요 의견을 참조하십시오.
Den

@ 기술적으로 인터페이스를 사용할 필요가 없습니다. 인터페이스는 단위 테스트를위한 조롱에 도움이됩니다. 가상을 조롱하는 데 필요한 것을 표시 할 수도 있습니다.
Fred
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.