ctor 또는 메소드별로 의존성을 주입해야합니까?


16

치다:

public class CtorInjectionExample
{
    public CtorInjectionExample(ISomeRepository SomeRepositoryIn, IOtherRepository OtherRepositoryIn)
    {
        this._someRepository = SomeRepositoryIn;
        this._otherRepository = OtherRepositoryIn;
    }

    public void SomeMethod()
    {
        //use this._someRepository
    }

    public void OtherMethod()
    {
        //use this._otherRepository
    }
}

에 맞서:

public class MethodInjectionExample
{
    public MethodInjectionExample()
    {
    }

    public void SomeMethod(ISomeRepository SomeRepositoryIn)
    {
        //use SomeRepositoryIn
    }

    public void OtherMethod(IOtherRepository OtherRepositoryIn)
    {
        //use OtherRepositoryIn
    }
}

Ctor 주입은 확장을 어렵게하지만 (새로운 의존성이 추가 될 때 ctor를 호출하는 모든 코드는 업데이트가 필요합니다) 메소드 레벨 주입은 클래스 레벨 종속성에서 더 캡슐화 된 것으로 보이며 이러한 접근법에 대한 다른 인수를 찾을 수 없습니다 .

주사를 위해 결정적인 접근 방법이 있습니까?

(NB 나는 이것에 대한 정보를 찾고이 질문을 객관적으로 만들려고 노력했습니다.)


4
클래스가 응집력이 있다면 많은 다른 메소드가 동일한 필드를 사용합니다. 이것은 당신에게 당신이 찾는 답을 줄 것입니다 ...
Oded

@Oded 좋은 지적, 응집력은 결정에 크게 영향을 미칩니다. 예를 들어, 클래스가 서로 다른 의존성을 가진 도우미 메서드 모음 (겉으로는 응집력은 없지만 논리적으로 유사 함)이 있고 다른 클래스는 매우 응집력이 높으면 가장 유익한 방법을 사용해야합니다. 그러나 이로 인해 솔루션간에 불일치가 발생할 수 있습니다.
StuperUser

내가 제공 한 예와 관련 : en.wikipedia.org/wiki/False_dilemma
StuperUser

답변:


3

주입 된 객체가 클래스에서 둘 이상의 메소드에 의해 사용되고 각 메소드에 주입되는 것이 의미가 없다면 모든 메소드 호출에 대한 종속성을 해결해야하지만 종속성이 생성자에 삽입하는 한 가지 방법은 좋지 않지만 결코 사용할 수없는 리소스를 할당하기 때문입니다.


15

우선, "새로운 의존성이 추가 될 때 ctor를 호출하는 모든 코드를 업데이트해야합니다"를 다루겠습니다. 분명히, 의존성 주입을하고 있고 의존성이있는 객체에서 new ()를 호출하는 코드 가 있다면 잘못하고 있습니다 .

DI 컨테이너는 모든 관련 종속성을 주입 할 수 있어야하므로 생성자 서명 변경에 대해 걱정할 필요가 없으므로 인수가 실제로 유지되지 않습니다.

방법 별 및 클래스 별 주입 아이디어는 방법 당 주입과 관련하여 두 가지 주요 문제가 있습니다.

한 가지 문제는 클래스의 메소드가 종속성을 공유해야한다는 것입니다.이 클래스는 많은 종속성 (아마도 4-5 이상)이있는 클래스를 볼 경우 클래스가 주요 후보입니다. 클래스가 효과적으로 분리되도록하는 한 가지 방법입니다 두 클래스로 리팩토링합니다.

다음 문제는 메소드마다 의존성을 "주입"하기 위해 메소드 호출에 의존성을 전달해야한다는 것입니다. 즉, 메소드 호출 전에 종속성을 해결해야하므로 다음과 같은 코드가 생길 수 있습니다.

var someDependency = ServiceLocator.Resolve<ISomeDependency>();
var something = classBeingInjected.DoStuff(someDependency);

이제 애플리케이션 주변 10 곳에서이 메소드를 호출한다고 가정 해 보겠습니다.이 스 니펫 중 10 개가 있습니다. 다음으로 DoStuff ()에 다른 종속성을 추가해야한다고 가정하십시오. 스 니펫을 10 번 변경하거나 메소드로 래핑해야합니다.이 경우 DI 동작을 수동으로 복제하는 것입니다. 시간).

따라서 기본적으로 수행 한 일은 DI 활용 클래스가 자체 DI 컨테이너를 인식하게 만드는 것입니다. 이는 근본적으로 나쁜 생각 입니다. 유지하기 어려운 어려운 디자인으로 매우 빨리 이어지기 때문입니다.

이것을 생성자 주입과 비교하십시오. 생성자 주입에서는 특정 DI 컨테이너에 묶여 있지 않으며 클래스의 종속성을 직접 수행 할 책임이 없으므로 유지 관리가 상당히 어렵습니다.

관련없는 도우미 메소드가 포함 된 클래스에 IoC를 적용하려고하는 것처럼 들리지만 사용법에 따라 도우미 클래스를 여러 서비스 클래스로 분할 한 다음 도우미를 사용하여 전화. 이것은 여전히 ​​훌륭한 접근 방식은 아니지만 (일반적으로 잘못 작성된 서비스 클래스에 전달되는 인수를 처리하는 것보다 복잡한 것을 수행하는 메소드로 분류되는 도우미), 최소한 디자인을 조금 더 깨끗하게 유지합니다. .

(NB 이전에 제안한 접근 방식을 수행했으며 그 이후로 반복하지 않은 것은 매우 나쁜 생각이었습니다. 실제로 분리 할 필요가없는 클래스를 분리하려고했지만 결국 각 메소드 호출이 다른 인터페이스를 거의 고정적으로 선택해야하는 일련의 인터페이스가 있습니다.


1
"if you're doing dependency injection and you have any code calling new() on an object with dependencies, you're doing it wrong."클래스에서 메소드를 단위 테스트하는 경우 메소드를 인스턴스화해야합니까 아니면 DI를 사용하여 테스트중인 코드를 인스턴스화합니까?
StuperUser

@StuperUser Unit 테스트는 약간 다른 시나리오이며 내 의견은 실제로 프로덕션 코드에만 적용됩니다. 미리 구성된 동작과 일련의 가정 및 주장이있는 모의 프레임 워크를 통해 테스트에 대한 모의 (또는 스텁) 종속성을 만들려면 직접 손으로 주입해야합니다.
Ed James

1
그것이 내가 말할 때 말하는 코드입니다. "any code calling the ctor will need updating"제작 코드는 ctor를 호출하지 않습니다. 이러한 이유들로.
StuperUser

2
@StuperUser Fair 충분하지만 필요한 종속성으로 메소드를 계속 호출 할 것이므로 나머지 답변은 여전히 ​​유효합니다! 솔직히 말하면, 나는 단위 테스트 관점에서 생성자 주입과 모든 의존성을 강요하는 문제에 동의합니다. 나는 속성 주입을 사용하는 경향이 있습니다. 이것은 테스트에 필요한 종속성 만 주입 할 수 있기 때문에 실제로 코드를 작성할 필요없이 암시 적 Assert.WasNotCalled 호출의 또 다른 세트입니다! : D
Ed James

3

다양한 종류의 제어 반전이 있으며 귀하의 질문은 두 가지만을 제안합니다 (공장을 사용하여 종속성을 주입 할 수도 있음).

답은 필요에 달려 있습니다. 때로는 한 종류와 다른 종류를 사용하는 것이 좋습니다.

생성자가 객체를 완전히 초기화하기 때문에 생성자 인젝터를 개인적으로 좋아합니다. 나중에 setter를 호출해야 객체가 완전히 구성되지 않습니다.


3

당신은 적어도 저에게 가장 융통성있는 주입이라는 것을 놓쳤습니다. Castle / Windsor를 사용하면 클래스에 새로운 자동 속성을 추가하기 만하면 문제없이 인터페이스를 중단하지 않고 주입 된 객체를 얻을 수 있습니다.


나는 웹 응용 프로그램에 익숙하며 이러한 클래스가 UI에 의해 호출되는 도메인 레이어에 있으면 속성 주입과 비슷한 방식으로 종속성이 이미 해결되었습니다. 주입 된 객체를 전달할 수있는 클래스를 처리하는 방법이 궁금합니다.
StuperUser

또한 속성 주입을 좋아하기 때문에 DI 컨테이너와 함께 일반 생성자 매개 변수를 계속 사용할 수 있으므로 해결 된 종속성과 해결되지 않은 종속성을 자동으로 구분할 수 있습니다. 그러나 생성자와 속성 주입은이 시나리오에서 기능적으로 동일하므로 언급하지 않기로 결정했습니다.)
Ed James

속성 주입은 모든 개체를 강제로 변경 가능하고 인스턴스를 유효하지 않은 상태로 만듭니다. 왜 바람직한가요?
Chris Pitman

2
@Chris 사실, 정상적인 조건에서 생성자와 속성 주입은 거의 동일하게 작동하며, 해상도 동안 객체가 완전히 주입됩니다. "유효하지 않은"것으로 간주 될 수있는 유일한 시간은 DI 컨테이너를 사용하여 구현을 인스턴스화하지 않을 때 단위 테스트 중입니다. 이것이 실제로 유익한 이유에 대한 내 답변에 대한 내 의견을 참조하십시오. 변경 가능성은 문제가 될 수 있지만 실제로는 인터페이스를 통해 확인 된 클래스 만 참조하므로 종속성이 편집되지 않습니다.
Ed James
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.