의존성 주입 대 정적 메소드


21

문자열을 받아들이고 문자열을 출력하는 메소드를 사용하여 클래스에 접근하는 방법에 대해 다른 개발자와 오늘 흥미로운 토론을했습니다.

다음과 같은 예를 위해 완전히 구성된 것을 상상해보십시오.

public string GetStringPart(string input)
{ 
   //Some input validation which is removed for clarity

   if(input.Length > 5)
        return input.Substring(0,1);

   if(input.Substring(0,1) == "B")
        return input.Substring(0,3);

   return string.empty;
}

문자열 입력을 기반으로 한 논리가있는 함수는 DI를 사용하여 프로젝트에 추가되고 DI 컨테이너가 있습니다. 이 새로운 클래스를 인터페이스와 함께 추가하고 필요한 곳에 주입하거나 정적 클래스로 만들겠습니까? 각각의 장단점은 무엇입니까? 왜 어디서나 필요할 때 액세스하지 않고 생성자 주입과 함께 사용하도록하고 싶습니까?


1
@Ewan 추상화에 사용되지 않는 도우미 메소드 용. 예 : Apache FileUtils.
Walfrat

3
@Ewan : 부작용이없는 정적 메소드는 이해하기 쉽고 테스트하기 쉽기 때문에 가장 좋은 방법입니다.
JacquesB

1
그러나 그것들은 그들에 의존하는 것을 단위 테스트하는 것을 불가능하게합니다
Ewan

3
@Ewan Eh, 실제로는 아닙니다. Math.Max ​​()는 정적이기 때문에 좋지 않습니까? 정적 메소드를 테스트하고 작동하는 경우 문제없이 다른 메소드에서 안전하게 사용할 수 있습니다. 정적 요소가 실패하면 테스트에서 문제를 포착합니다.
T. Sar-복원 모니카

1
'정적'이 부작용을 보장하지 않으면 인수를 볼 수 있습니다. 그러나 그렇지 않습니다.
Ewan

답변:


25

이것이 주입되어야 할 이유가 없습니다. 이것은 단지 함수 일 뿐이며 종속성이 없으므로 호출하십시오. 순수한 것처럼 보이길 원한다면 정적 일 수도 있습니다. 어려움없이 단위 테스트를 작성할 수 있습니다. 다른 클래스에서 사용되는 경우에도 단위 테스트를 작성할 수 있습니다.

의존성이없는 함수를 추상화 할 필요가 없습니다.

이것이 복잡해지면 인터페이스를 생성자 또는 메소드에 전달하는 것이 필요합니다. 그러나 GetStringPart위치 등을 기반으로 복잡한 논리 가 없다면 그 길을 따라 가지 않을 것입니다 .


2
이것이 정답입니다! 화물 숭배에 대한 해답이 받아 들여졌습니다.
JacquesB

3
함수에 의존성이 없다는 것이 요점이 아닙니다. 문제는 다른 것들이 그 기능에 의존하고 그것에 밀접하게 결합 될 때이다
Ewan

2
6 개월 안에 기능이 바뀌고 순수하지는 않지만 이미 많은 곳에서 사용되고 있다면 어떨까요? 정적으로 확장 할 수 없으며 클래스 테스트를 소비하는 클래스와 격리 할 수있는 것도 아닙니다. 약간의 변화 가능성이 있다면 주사로 갈 것입니다. 즉, 나는 반대 주장에 귀를 기울이고 있으며, 이것이이 포스트의 요점입니다. 이것에 대한 단점은 무엇입니까? 정적의 긍정적 인 점은 무엇입니까?
제임스

1
일반적으로,이 웹 사이트에서 의존성 주입을 논의하는 사람들은 의존성 주입이 필요하지 않습니다. 따라서 불필요한 복잡성에 대한 편견.
Frank Hileman

2
@James 함수의 순도가 떨어지면 뭔가 잘못한 것이므로 함수가 처음부터 제대로 정의되지 않았을 수 있습니다. 사각형의 면적을 계산할 때 갑자기 데이터베이스 호출이 필요하거나 UI에 대한 시각적 업데이트를 배포해서는 안됩니다. "Substring"메소드가 갑자기 불완전한 시나리오를 상상할 수 있습니까?
T.

12

이유는 다음과 같습니다

class DOSClient {
    OrderParser orderParser;
    string orderCode;

    DOSClient(OrderParser orderParser, string ordercode) { 
        this.orderParser = orderParser; 
        this.ordercode = ordercode;
    }
    void DisplayOrderCode() {
        Console.Write( "Prefix: " + orderParser.GetStringPart(ordercode) ); 
        ...
    }
}

class GUIClient {
    OrderParser orderParser;
    string orderCode;
    GUI gui;

    GUIClient(OrderParser orderParser, string ordercode, GUI gui) { 
        this.orderParser = orderParser; 
        this.ordercode = ordercode;
        this.gui = gui;
    }

    void DisplayOrderCode() {
        gui.Prefix( orderParser.GetStringPart(ordercode) ); 
        ...
    }
}

 

class OrderParserUS : IOrderParser {

    public string GetStringPart(string input)
    { 
        //Some input validation which is removed for clarity

        if(input.Length > 5)
            return input.Substring(0,1);

        if(input.Substring(0,1) == "B")
            return input.Substring(0,3);

        return string.empty;
    }
}

class OrderParserEU : IOrderParser {

    public string GetStringPart(string input)
    { 
        //Some input validation which is removed for clarity

        if(input.Length > 6)
            return input.Substring(0,1);

        if(input.Substring(0,1) == "#")
            return input.Substring(0,3);

        return string.empty;
    }
}

정적 방법을 사용 GetStringPart하면 이전 동작을 파괴하거나 조건부 논리로 오염시키지 않고 동작을 변경할 수있는 방법이 없습니다 . 정적은 변장에서 악의적 인 전역이라는 것이 사실이지만, 다형성을 비활성화한다는 사실은 그들에 대한 나의 주요 불만입니다. 정적 메소드는 OOP 언어에서 일류 클래스가 아닙니다. 메서드에 상태가없는 개체도 살도록 개체를 제공함으로써 메서드를 이식 가능하게 만듭니다. 변수의 값처럼 동작을 전달할 수 있습니다.

여기서 유럽에 배포 할 때와 미국에 배포 할 때 약간 다르게 작동해야하는 시스템을 상상했습니다. 그 대신 어느 한 시스템이 다른 시스템에 필요한 코드 만 포함하도록 강제 실행하면 클라이언트에 어떤 순서 구문 분석 오브젝트가 삽입되는지 제어하여 동작을 변경할 수 있습니다. 이를 통해 지역 세부 사항의 확산을 포함 할 수 있습니다. 또한 기존 파서를 건드리지 않고도 OrderParserCanada를 쉽게 추가 할 수 있습니다.

그것이 당신에게 아무런 의미가 없다면, 이것에 대한 좋은 주장은 실제로 없습니다.

BTW GetStringPart는 끔찍한 이름입니다.


* 괄호 코드 스타일에 영향을 미침 * C # 코드를 작성하려는 Java 프로그래머라고 생각하십니까? 내가 생각하는 것을 알고 있습니다. :)
Neil

질문은 언어에 국한된 것이 아니라 디자인에 관한 것입니다. 정적 메소드의 문제점은 테스트를 위해 코드를 분리하는 것을 방지한다는 것입니다. 내가 말한 개발자는 DI에 너무 많이 의존하고 때로는 확장 방법 / 정적 방법이 관련이 있다고 생각합니다. 나는 드문 경우이지만 일반적인 목적으로 생각하지 않습니다. 내가 느낀 토론은 계속 논의하기에 좋은 것이 었습니다. 나는 또한 다형성에 대한 당신의 경우에 동의합니다.
James

테스트는 이유가 있지만 더 있습니다. 테스트를 비난하는 사람들을 시작하기 때문에 테스트를 비난하는 것을 좋아하지 않습니다. 간단한 사실은 절차 적 프로그래밍을하지 않으면 절차 적 프로그래머는 그것을 좋아하지 않는다는 것입니다.
candied_orange

당신은 단순히 말할 수 static getStringPartEU()없습니까? 해당 클래스에 특수 EU 처리가 필요하고 단일 단위로 처리해야하는 다른 메소드가있는 경우에만 예가 적합합니다.
Robert Harvey

2
불필요한 복잡성에 찬성하여 분명히 주장하고 있습니다. 모든 것이 더 많은 코드를 추가 할 수 있습니다. 변경해야하는 사항은 수정하기 쉬워야하지만 향후 변경해야 할 사항을 예측해서는 안됩니다. 정적 필드는 전역 변수와 동일 할 수 있지만 정적 메소드는 순수하고 가능한 최상의 유형의 메소드 일 수 있습니다.
Frank Hileman 님이
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.