무국적에 대한 의미 적 단서로서 "정적"?


11

최근 Java로 돌아가서 단위 테스트를 추가하기 위해 중간 크기의 프로젝트를 리팩토링했습니다. 싱글 톤과 스태틱을 조롱하는 것이 얼마나 고통 스러운지 깨달았을 때, 나는이 시간 동안 내가 읽은 것을 마침내 "얻었다". (나는 경험을 통해 배워야 할 사람들 중 하나입니다. 아.)

이제 Spring을 사용하여 객체를 만들고 주변을 연결하고 있으므로 static키워드를 왼쪽과 오른쪽으로 제거 하고 있습니다. (잠재적으로 조롱하고 싶을 때 Math.abs ()와 같은 의미로 실제로 정적이지는 않습니까?) 문제는 static메서드가 의존하지 않았다는 것을 나타내는 습관을 사용 했습니다. 모든 객체 상태에서. 예를 들면 다음과 같습니다.

//Before
import com.thirdparty.ThirdPartyLibrary.Thingy;
public class ThirdPartyLibraryWrapper {
    public static Thingy newThingy(InputType input) {
         new Thingy.Builder().withInput(input).alwaysFrobnicate().build();
    }
}

//called as...
ThirdPartyLibraryWrapper.newThingy(input);
//After
public class ThirdPartyFactory {
    public Thingy newThingy(InputType input) {
         new Thingy.Builder().withInput(input).alwaysFrobnicate().build();
    }
}

//called as...
thirdPartyFactoryInstance.newThingy(input);

그래서 여기가 손에 닿는 곳이 있습니다. 대문자가 Math.sin (x)와 마찬가지로 ThirdPartyLibraryWrapper.newThingy (x)는 매번 같은 방식으로 같은 방식을 사용한다고 말했기 때문에 이전 방식이 마음에 들었습니다. 객체가 요청한 것을 수행하는 방식을 변경할 객체 상태가 없습니다. 내가 고려하고있는 가능한 답변은 다음과 같습니다.

  • 아무도 이런 식으로 느끼지 않아 나에게 문제가 있습니다. 어쩌면 나는 실제로 일을하는 OO 방식을 내면화하지 않았을 것입니다! 어쩌면 나는 Java로 작성하고 있지만 FORTRAN 등을 생각하고 있습니다. (내가 FORTRAN을 쓴 적이 없으므로 인상적 일 것입니다.)
  • 어쩌면 코드에 대한 추론을 목적으로 불변성의 프록시로 정적을 사용하고 있습니다. 즉, 누군가 상태를 유지하고 무엇이 아닌지 알기 위해 코드를 유지하기 위해 내 코드에 어떤 단서 가 있어야 합니까?
  • 아마도 좋은 객체 은유를 선택하면 이것이 무료로 제공되어야합니까? 예를 들어 thingyWrapper랩핑 된 상태에 무관 한 상태로 들릴 수있는 것처럼 들리지 않습니다 Thingy. 마찬가지로, thingyFactory소리가 변하지 않는 것처럼 들리지만 창조 과정에서 다른 전략을 선택할 수 있습니다.

답변:


12

대문자가 Math.sin (x)와 마찬가지로 ThirdPartyLibraryWrapper.newThingy (x)는 매번 같은 방식으로 같은 방식을 사용한다고 말했기 때문에 이전 방식이 마음에 들었습니다. 객체가 요청한 것을 수행하는 방식을 변경할 객체 상태가 없습니다.

그것이 올바른 방법입니다. 즉, static불변성 또는 상태 지속성을 보장하지 않습니다. 그러한 보증에 대한 제안으로 사용하는 것은 의미가 있지만 결코 보장되지는 않습니다.

다음을 고려하세요:

public static class Logger
{
    public static int LogLevel { get; set; }

    public static void Log(string message, int logLevel)
    {
        if (logLevel >= LogLevel)
        {
            // logs the message, but only if it is important enough.
        }
    }
}

이 클래스는 상태를 유지할뿐만 아니라 Logger.Log()상태가 변경 될 때 메소드 의 동작 이 변경됩니다. 그것은 static클래스 패턴 의 완벽한 합법적 인 운동 이지만 제안하는 의미 론적 보장은 없습니다.


직관을 바탕으로 유용한 반론을 제시하기 때문에 확인 표시를했지만 코딩을 통한 상태 부족 및 부작용 부족에 대한 계약 / 예상을 어떻게 표현해야하는지에 대한 의견을 여전히 갖고 싶습니다. 컨벤션.
leoger

1
일반적으로 이러한 기대치는 방법에 대한 문서에 포함됩니다. 나사산 안전도 마찬가지입니다.
Robert Harvey

5

내 의견으로는, 모든 정적 함수가 nullipotent라는 말은 대부분의 경우 코드를 작성하는 좋은 OO 방법이지만 정적 함수를 볼 때 부작용이 없다고 자동으로 가정해야한다고 생각하지 않습니다. . 상황이 더 복잡 할 수 있습니다. 예를 들어 Class.forName(String)상태 비 저장 인 것처럼 보이지만 실제로 클래스를 메모리에로드하고 결국 정적 필드를 인스턴스화하고 정적 초기화 프로그램을 실행 하는 함수를 예로들 수 있습니다. 이것은 dem 등원 함수 (첫 번째 함수 이후의 최종 호출은 차이가 없음)의 예이지만 순수한 함수는 아닙니다 (부작용이 없다고 말할 수는 없습니다). 이것은 또한 좋은 선택이지만 동일한 함수에 대한 세 개의 개별 호출이 세 개의 다른 결과를 생성하는 경우가 있습니다. 예를 들어 전화하면Thread.currentThread() 다중 스레드 응용 프로그램에서는 매번 동일한 스레드를 수신한다고 보장 할 수 없습니다.

즉, 누군가 상태를 유지하고 무엇이 아닌지 알기 위해 코드를 유지하기 위해 내 코드에 어떤 단서가 있어야합니까?

적절한 해결책은 문서화하는 것입니다 (예 : Javadoc). 또한 함수의 이름과 그 기능에 따라 정적 함수가 순수한 함수라고 추론 할 수 있습니다. 예를 들어 누군가 Assert.assertTrue(boolean)JUnit에서 어떤 상태를 변경 한다고 믿을 이유가 없습니다 . 반면에 같은 함수 System.clearProperty(String)가 호출되면 부작용이있을 것입니다.


"nullipotent"와 "stateless"의 차이점은 무엇입니까?
Pacerier

@Pacerier 아무런 차이가 없어야합니다.
m3th0dman 2016

4

즉, 누군가 상태를 유지하고 무엇이 아닌지 알기 위해 코드를 유지하기 위해 내 코드에 어떤 단서가 있어야합니까?

그것들을 정적으로 만들 수 있습니다. C # 세계에서 FxCop over를 사용하면 참조 멤버 변수가없는 정적 요소를 만들 수 있습니다. 이것은 (보통) 올바른 일입니다.

싱글 톤과 스태틱을 조롱하는 것이 얼마나 고통 스러운지 깨달았을 때, 나는이 시간 동안 내가 읽은 것을 마침내 "얻었다".

모든 인스턴스를 인스턴스로 옮기는 것이 올바른 접근법이 아닐 수도 있습니다. 대신 정적 메서드에 대한 종속성을 해당 메서드를 사용하는 클래스에서 분리하십시오. 정적 메서드를 격리하여 테스트 한 다음 소비자가 테스트해야 할 때 종속성을 대체 할 수 있습니다.


"정적 메소드에 대한 의존성 분리"의 예를 보여줄 수 있습니까? 당신이 무엇을 활성화하고 있는지 분명하지 않습니다. 정적 메서드에서 구현 세부 정보를 이미 숨겼습니다. 하루가 끝나면 클래스를 사용 하는 클래스가 해당 기능 에 도달 해야합니다. 모든 정적 메서드에 대해 얇은 래퍼가있는 인스턴스 객체를 만들어야한다고 말하고 있습니까?
leoger

1
@leoger-정적 메소드를 사용하는 클래스는 해당 클래스를 테스트하는 경우 기능에 도달 할 필요가 없습니다. 그렇지 않으면 정적 메소드를 조롱하지 않아도됩니다.
Telastyn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.