"정적 인터페이스"가 좋은 습관입니까?


13

최근에 인터페이스에 정적 메소드를 갖는 옵션이 있음을 알았습니다. 정적 인터페이스 필드와 마찬가지로 흥미로운 동작이 있습니다. 상속되지 않습니다.

구현할 실제 인터페이스에서 유용하다는 확신이 없습니다. 그러나 프로그래머는 유틸리티 클래스와 같이 정적 요소를위한 엔벨로프 인 인터페이스를 작성할 수 있습니다.

간단한 예는 전역 상수를위한 봉투입니다. 클래스와 비교할 때 누락 된 보일러 플레이트를 쉽게 알아볼 수 있습니다 public static final.

public interface Constants {
    String LOG_MESSAGE_FAILURE = "I took an arrow to the knee.";
    int DEFAULT_TIMEOUT_MS = 30;
}

이 가상 키 구성 키와 같이 더 복잡한 것을 만들 수도 있습니다.

public interface ConfigKeys {
    static createValues(ConfigKey<?>... values) {
        return Collections.unmodifiableSet(new HashSet(Arrays.asList(values)));
    }

    static ConfigKey<T> key(Class<T> clazz) {
        return new ConfigKey<>(clazz);
    }

    class ConfigKey<T> {
        private final Class<T> type;
        private ConfigKey(Class<T> type) {
            this.type = type;
        }
        private Class<T> getType() {
            return type;
        }
    }
}

import static ConfigKeys.*;
public interface MyAppConfigKeys {
    ConfigKey<Boolean> TEST_MODE = key(Boolean.class);
    ConfigKey<String> COMPANY_NAME = key(String.class);

    Set<ConfigKey<?>> VALUES = createValues(TEST_MODE, COMPANY_VALUE);

    static values() {
        return VALUES;
    }
}

이런 식으로 유틸리티 "클래스"를 만들 수도 있습니다. 그러나 유틸리티에서는 개인 또는 보호 된 헬퍼 메소드를 사용하는 것이 유용하지만 클래스에서는 불가능합니다.

나는 이것이 새로운 기능이라고 생각합니다. 특히 정적 멤버가 상속되지 않았다는 사실은 인터페이스에만 소개 된 흥미로운 개념입니다.

좋은 습관으로 생각할 수 있는지 궁금합니다. 코드 스타일과 모범 사례는 공리적이지 않으며 의견의 여지가 있지만 일반적으로 의견을 뒷받침하는 정당한 이유가 있다고 생각합니다.

나는이 두 가지와 같은 패턴을 사용하는 이유에 더 관심이 있습니다.


해당 인터페이스를 구현하지는 않습니다. 정적 콘텐츠를위한 봉투 일뿐입니다. 상수 또는 메소드 만 사용하고 정적 가져 오기를 사용하려고합니다.


1
이것에 대한 저의 무릎 저크 반응은 나쁜 일로 이어질 수 있다는 것입니다. 공용 정적 메소드는 본질적으로 네임 스페이스가 지정된 전역 함수 일지라도. 인터페이스의 구현 코드를 허용하지 않으면 계약 정의가 구현의 목적과 반대되는 느낌이 듭니다. 추상 클래스에는 부분 구현을 남겨 둡니다. 이것이 추가 된 이유를 읽어야합니다.
Adrian

나는 지금 가야하지만 내일 무언가를 쓸 것이다. 인터페이스의 명확한 목적이 AbstractClass의 목적과 명확하게 분리되기 전에는 부족합니다. 이제 인터페이스의 언어 독립적 인 정의를 위반하는 방식으로 크게 겹칩니다. 또한 기본 메소드를 구현하는 경우 더 이상 여러 인터페이스에서 상속 할 수없는 경우가 있습니다. 따라서 지금까지 없었던 다중 인터페이스 상속에는 예외가 있습니다. 자바가 인터페이스의 일반적인 정의에서 크게 벗어난 이후로 ...
Adrian

또한 인터페이스, AbstractClases, 상속 대신 컴포지션 사용시기 등과 같은 기본 OOP 개념을 올바르게 처리하려는 새로운 개발자를 혼란스럽게 할 수 있습니다.
Adrian

Aliester, 당신은 default방법 에 대해 이야기하고 있습니다. 나는 static방법과 분야 에 대해 이야기 하고 있습니다. 그것들은 상속되지 않으므로 다중 상속을 중단하지 않습니다.
Vlasec

답변:


1

간단한 예는 전역 상수를위한 봉투입니다.

Constant Interface Antipattern상수는 종종 구현 세부 사항이므로 인터페이스에 상수를 넣는 것을 호출합니다 . 추가 단점은 Constant 인터페이스 의 Wikipedia 기사에 요약되어 있습니다 .

이런 식으로 유틸리티 "클래스"를 만들 수도 있습니다.

실제로 Java doc에 따르면 정적 메소드는 기본 메소드에서 헬퍼 메소드를 호출 할 때와 같이 헬퍼 메소드를보다 쉽게 ​​구성 할 수 있다고합니다.


1
나는 이것이 새로운 기능없이 두 가지를 모두 할 수 있기 때문에 실제로 제기 된 질문에 대한 답변이라고 생각하지 않습니다.
Adrian

아, 문서에 따르면 도우미 방법으로 작성되었습니다. 그러나 그것은 또한 공개적이어서 모순된다. 따라서 인터페이스를 구현하는 클래스를 돕는 것이 목적 일 수도 있습니다. 그러나 그들은 상속받지 않으므로 상속 된 것처럼 느끼게하려면 정적 가져 오기를 사용해야합니다. 문서에서 찾아 주셔서 감사합니다.
Vlasec

2
상수가 인터페이스에 의해 설명 된 API의 일부인 경우 인터페이스에 상수를 넣는 것은 절대로 아무 문제가 없습니다. 반 패턴 인 유일한 방법은 메서드없이 인터페이스에 상수를 넣고 클래스 접두사가없는 상수 만 참조하도록 인터페이스를 구현하는 클래스입니다. 인터페이스를 남용하고 정적 가져 오기가 도입 된 이후 완전히 사용되지 않습니다.
Michael Borgwardt

1

질문에서 언급했듯이 인터페이스는 구현 (또는 인스턴스화)되지 않습니다. 따라서 개인 생성자가있는 클래스와 비교할 수 있습니다.

  • 클래스는 super()호출 할 필요없이 확장 할 수 없지만 인터페이스는 "구현 될 수 있습니다"
  • 클래스는 리플렉션없이 인스턴스화 할 수 없지만 인터페이스는 다음과 같이 간단하게 익명 클래스로 인스턴스화 할 수 있습니다. new MyInterface() {};

이 비교는 더 많은 제어를 허용하므로 클래스에 유리합니다. 즉, 클래스는 정적 요소의 홀더가 아니며 인스턴스가있을 것으로 예상됩니다. 완벽한 옵션은 없습니다.

"정적 인터페이스"의 상속에 대한 이상한 점이 있습니다.

  • "구현"클래스는 필드를 상속하지만 정적 메소드는 상속하지 않습니다.
  • 확장 인터페이스는 정적 멤버를 전혀 상속하지 않습니다.
  • (클래스를 확장하는 클래스는 개인이 아닌 모든 멤버를 상속하지만 인터페이스로 확장 할 수 없으므로 혼동의 여지가 적습니다)

이것이 잘못된 패턴으로 간주하고 이러한 경우에 정적 클래스를 계속 사용하는 이유 일 수 있습니다. 그러나 구문 설탕에 중독 된 사람에게는 여전히 단점이 있지만 유혹적 일 수 있습니다.


어쨌든 팀의 코딩 규칙은 이러한 문제를 다룰 수 있습니다. 나에게는 개인 생성자가있는 클래스와 거의 비슷하게 프로그래머의 손을 묶지 않지만 세터보다 위험이 적으며 세터가 자주 사용됩니다.
Vlasec

0

@MarkusPscheidt로서이 아이디어는 본질적으로 Constant Interface 반 패턴 의 확장입니다 . 이 접근 방식은 처음에 여러 다른 클래스에서 단일 상수 세트를 상속 할 수 있도록 널리 사용되었습니다. 이것이 반 패턴으로 간주되는 이유는 실제 프로젝트에서이 접근법을 사용하여 발생한 문제 때문입니다. 나는 이러한 문제들이 상수와 관련이 있다고 생각할 이유가 없다.

아마도 더 중요한 것은 실제로 이것을 할 필요가 없다는 것입니다. 사용 정적 수입을 대신 당신이 가져 오는 것에 대해 어디에서 명시.


예, 정적 가져 오기는 상수 상속보다 더 좋은 아이디어처럼 들리며 클래스와 인터페이스의 정적 멤버와 함께 작동합니다. 클래스 / 인터페이스에서만 볼 수 있습니다.
Vlasec

@Vlasec 맞지만 인터페이스 에서이 작업을 수행 할 필요는 없습니다. 클래스와 인터페이스를 사용하여이 작업을 수행하는 것의 유일한 차이점은 둘 이상의 인터페이스에서 상속 할 수 있다는 것입니다. 이와 같은 유틸리티 클래스의 표준 사례는 인스턴스 생성 또는 확장을 방지하기 위해 생성자를 비공개로 만드는 것입니다. 클래스를 통한 인터페이스에서이 작업을 수행하면 이점이 없습니다. 그것은 단순히 오용의 문을 엽니 다.
JimmyJames

인터페이스의 상수 값을 볼 수 있습니다. 인터페이스는 메소드를 정의하는 경향이 있으며 메소드는 때때로 상수를 매개 변수로 받아들입니다. 예 : interface ColorFilter {Image applyGradient(int colorSpace, int width, byte[] pixels); }. 나는 거기 상상할 수있는 몇 가지 다른 상수 RGB, RGBA, CMYK, GREYSCALE, INDEXED
스테인 드 위트

@StijndeWitt 최악의 상황은 아니지만 인터페이스에 열거 형 또는 중첩 클래스를 사용할 수 있습니다. 실제 문제는 상속을 통해 정적을 여러 클래스의 범위로 가져 오는 데 사용하는 것입니다. 이 방법은 정적 가져 오기를 사용하는 것보다 열등합니다.
JimmyJames

0

새 기능을 올바르게 사용하는 방법에 관심이 있다면 JDK의 코드를 살펴보십시오. 인터페이스의 기본 메소드는 매우 널리 사용되고 쉽게 찾을 수 있지만 인터페이스의 정적 메소드는 매우 드문 것으로 보입니다. 몇 가지 예는 java.time.chrono.Chronology, java.util.Comparator, java.util.Map, 그리고 꽤 많은 인터페이스를 java.util.function하고 java.util.stream.

내가 본 대부분의 예제는 매우 일반적인 API를 사용하는 것과 관련이 있습니다. 예를 들어, 시간 API의 다른 유형 간 변환, 예를 들어 함수 또는 객체에 포함 된 객체 사이에 자주 수행 될 가능성이있는 비교 컬렉션. 내 테이크 아웃 : API의 일부가 유연해야하지만 소수의 기본값으로 사용 사례의 80 %를 다룰 수 있다면 인터페이스에서 정적 메소드를 사용하는 것이 좋습니다. 이 기능이 JDK에서 드물게 사용되는 것처럼 보이면 내 코드에서이 기능을 사용할 때 매우 보수적입니다.

귀하의 예제는 JDK에서 보는 것과 비슷하지 않습니다. 이러한 특정 경우, enum원하는 인터페이스를 구현 하는 것을 작성해야합니다 . 인터페이스는 일련의 동작을 설명하며 실제로 구현 모음을 유지 관리하는 비즈니스는 없습니다.


-1

그것을 사용하지 않는 이유가 있는지 궁금합니다.

오래된 JVM과의 호환성은 어떻습니까?

이것이 일반적으로 좋은 생각이라고 생각하십니까?

아니요. 언어의 표현성에 zilch를 추가하는 이전 버전과 호환되지 않는 변경입니다. 두 엄지 손가락을 아래로 내립니다.

수업을 강력히 추천하는 모델 상황이 있습니까?

클래스를 사용하여 구현 세부 정보를 포함하는 것이 좋습니다. 인터페이스는 실제로 "이 객체는 XYZ 작업을 지원합니다"라는 의미로 사용되며 인터페이스 선언에 넣을 것으로 생각되는 정적 메서드와는 아무런 관련이 없습니다. 이 기능은 미니 냉장고가 내장 된 안락 의자와 같습니다. 물론 틈새 사용이 있지만 주류가 될만한 무게를 충분히 얻지 못합니다.

업데이트 : 더 이상 하향 투표하지 마십시오. 분명히 어떤 사람들은 인터페이스의 정적 메소드가 꿀벌의 무릎이라고 생각합니다. 나는이 답변을 빨리 삭제하지만 그것에 첨부 된 의견은 흥미로운 토론입니다.


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
maple_shaft

내가 당신의 질문을 downvoted한다면, 우리의 첫 두 답변은 실제 답변이 아니기 때문에 그렇게 할 것입니다. 새로운 언어 버전은 새로운 도구를 제공하여 작업을보다 쉽게 ​​만들어줍니다. 이것이 바로 새 버전의 목적입니다. 세 번째 대답은 파열 된 처음 두 사람의 잔해에서 다소 사라졌습니다.
Vlasec
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.