답변:
정적 멤버를 인터페이스에 배치 (및 해당 인터페이스 구현) 하는 것은 나쁜 습관 이며 이름 인 Constant Interface Antipattern 도 있습니다. 효과적인 Java , 항목 17을 참조하십시오 .
상수 인터페이스 패턴은 인터페이스를 제대로 사용하지 않는 것입니다 . 클래스가 내부적으로 일부 상수를 사용한다는 것은 구현 세부 사항입니다. 상수 인터페이스를 구현하면이 구현 세부 사항이 클래스의 내 보낸 API로 유출됩니다. 클래스가 상수 인터페이스를 구현하는 것은 클래스 사용자에게 중요하지 않습니다. 사실, 혼란 스러울 수도 있습니다. 더 나쁜 것은 약속을 나타냅니다. 향후 릴리스에서 더 이상 상수를 사용할 필요가 없도록 클래스가 수정되는 경우에도 이진 호환성을 보장하기 위해 인터페이스를 구현해야합니다. 최종 클래스가 아닌 클래스가 상수 인터페이스를 구현하는 경우 모든 하위 클래스는 인터페이스의 상수에 의해 네임 스페이스가 오염됩니다.
Java 플랫폼 라이브러리에는
java.io.ObjectStreamConstants
. 이러한 인터페이스는 이상 징후로 간주되어야하며 에뮬레이션해서는 안됩니다.
상수 인터페이스의 일부 함정을 피하려면 (사람들이 구현하는 것을 막을 수 없기 때문에) 개인 생성자가있는 적절한 클래스를 선호해야합니다 (예 : Wikipedia 에서 빌림 ).
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
정규화 할 필요없이 (즉, 클래스 이름을 접두사로 지정할 필요없이) 상수에 액세스하려면 정적 가져 오기 (Java 5부터)를 사용하십시오.
import static Constants.PLANCK_CONSTANT;
import static Constants.PI;
public class Calculations {
public double getReducedPlanckConstant() {
return PLANCK_CONSTANT / (2 * PI);
}
}
" 지속적인 인터페이스 패턴은 인터페이스를 잘 사용하지 않습니다. "
이 가설을 만든 사람은 누구든지 그 / 그녀가 전문가 일 수 있지만 나쁜 습관과 관행을 효율적으로 구현해야한다는 필요성을 기반으로 만들어졌습니다. 가설은 잘못된 소프트웨어 설계 습관의 타당성을 홍보하는 데 기반을두고 있습니다.
저는 여기에 그 가설에 대한 반박을 썼습니다. Java에서 상수를 구현하는 가장 좋은 방법은 무엇입니까? 이 가설의 근거 없음을 설명합니다.
내가이 가설을 정당화 한 이유를 게시 한 후 2 시간 이내에 그 질문이 닫힐 때까지 10 년 동안 그 질문은 열려 있었으며,이 잘못된 가설을 몹시 고수하는 사람들의 논쟁에 대한 UNWILLINGness를 드러 냈습니다.
이것이 제가 가설에 반하여 표현한 점입니다.
이 가설을 유지하는 기초는 나쁜 소프트웨어 습관과 방법론의 영향에 대처하기위한 방법과 제한적 규칙이 필요하다는 것입니다.
" 일관된 인터페이스 패턴은 인터페이스를 제대로 사용 하지 않는다 " 라는 정서의 지지자들은 그러한 나쁜 습관과 관행의 영향에 대처할 필요가있는 이유 이외의 다른 이유를 제공 할 수 없습니다.
근본적인 문제를 해결하십시오.
그리고 Java 언어 구조의 모든 언어 기능을 최대한 활용하고 자신의 편의를 위해 활용하는 것은 어떻습니까? 재킷이 필요하지 않습니다. 왜 더 효과적인 라이프 스타일을 차별하고 유인하기 위해 당신의 비효율적 인 라이프 스타일을 막는 규칙을 발명합니까?
정보 조직입니다. 프로세스에 대한 솔루션을 엔지니어링하거나 보완하기 전에 프로세스를 매개하는 정보와 해당 정보의 동작을 소위 비즈니스 규칙과 함께 먼저 이해해야합니다. 이러한 정보 구성 방법은 수십 년 전에 데이터 정규화라고 불 렸습니다.
그러면 솔루션 구성 요소의 세분성 및 모듈성을 정보 구성 요소의 세분성 및 모듈 성과 일치시키는 것이 최적의 전략이기 때문에 솔루션의 엔지니어링 만 가능합니다.
정보를 구성하는 데 두세 가지 중요한 장애물이 있습니다.
데이터 모델 "정규화"의 필요성에 대한 인식 부족.
데이터 정규화에 대한 EF Codd의 진술은 결함이 있고 결함이 있으며 모호합니다.
애자일 엔지니어링으로 가장 한 최신 유행은 진행하면서 리팩토링 할 수 있기 때문에 앞으로의 모듈 구성을 계획하고 조정해서는 안된다는 잘못된 생각입니다. 미래의 발견에 지장을받지 않는 리팩토링과 지속적인 변화가 변명으로 사용됩니다. 프로세스 정보의 행동에 대한 필수적인 발견은 회계 속임수를 사용하여 수익과 자산화를 지연시키는 것입니다. 따라서 지금은 필수적인 지식과 그 처리가 필요하지 않은 것으로 간주됩니다.
임시 뺑소니 프로그래밍 습관을 좋아한다고해서 규칙을 만들거나 그것에 반대하는 어떤 조치도하지 마십시오.
총을 다루는 방법을 모르거나 총을 남용하는 경향이있는 사람들이 있다는 이유로 총 소유권을 금지하지 마십시오.
당신이 만든 규칙이 전문적으로 코딩 할 수없는 프로그래밍 초보자를위한 것이고 그들 사이에서 당신 자신을 생각한다면 그렇게 말하십시오-당신의 fatwa를 적절하게 정규화 된 데이터 모델에 적용 할 수 있다고 선언하지 마십시오.
저는 미국 헌법에 대한 건국의 아버지들의 원래 의도가 무엇인지 상관하지 않습니다. 나는 문서화되지 않은 의도를 신경 쓰지 않는다. 나는 서면 헌법에 문자 적으로 성문화 된 내용과 사회의 효과적인 기능을 위해 어떻게 활용할 수 있는지에 만 관심이 있습니다.
저는 Java 언어 / 플랫폼 사양이 허용하는 것에 만 관심이 있고이를 최대한 활용하여 소프트웨어 솔루션을 효율적이고 효과적으로 표현할 수있는 매체를 제공 할 계획입니다. 재킷이 필요하지 않습니다.
매개 변수를 값에 매핑하려면 추가 코드를 작성해야합니다. Java의 창립자가 사용자가 작성하지 않고는 매개 변수 값 맵핑을 제공하지 않았다는 사실은 맵핑 코드가 Enum 상수를 보여 준다는 사실은 의도하지 않은 Java 언어 사용과 같습니다.
특히 매개 변수를 정규화하고 구성 요소 화하도록 권장하지 않기 때문에 Enum 백에 혼합 된 매개 변수가 동일한 차원에 속한다는 잘못된 인상이있을 수 있습니다.
잊지 마세요. 데이터 모델을 설계하고 정규화하고 여기에 상수가 포함 된 경우 해당 상수는 계약입니다. 데이터 모델을 정규화하지 않았다면 그 나쁜 습관에 대처하기 위해 제한적 코딩을 연습하는 방법에 대한 fatwas를 준수해야합니다.
따라서 인터페이스는 Constants의 계약을 구현하는 완벽한 방법입니다.
예. 누구나 실수로 인터페이스를 실수로 구현할 수 있습니다. 그러한 부주의 한 프로그래머를 방해하는 것은 없습니다.
계약되지 않은 / 잘못된 매개 변수가 API로 유출되는 원인이 될 것으로 추정되는 나쁜 관행을 보호하기 위해 제한적인 법령을 두지 마십시오. 인터페이스 상수를 비난하기보다는 근본적인 문제를 해결하십시오.
정상적인 기능과 효과적인 프로그래머는 그녀가 수중에 얼마나 오래 머물 수 있는지, 맹렬한 더위 나 습한 뇌우 속에서 얼마나 멀리 걸을 수 있는지 증명하기 위해 거기에 있지 않습니다. 그녀는 매일 10 마일을 일하기 위해 자동차 나 버스 또는 최소한 자전거와 같은 효율적인 도구를 사용해야합니다.
IDE없는 프로그래밍에 대한 난해한 금욕주의에 집착한다고해서 동료 프로그래머에게 제한을 두지 마십시오.
OSGI는 그러한 프레임 워크입니다. 인터페이스 상수에 대한 법령도 마찬가지입니다.
인터페이스 상수는 데이터 모델의 잘 디자인되고 정규화 된 구성 요소를 계약에 배치하는 효과적이고 효율적인 방법입니다.
클래스 파일에 중첩 된 적절하게 이름이 지정된 개인 인터페이스의 인터페이스 상수는 파일 전체에 분산되지 않고 모든 개인 상수를 그룹화하는 좋은 방법입니다.
나는이 오래된 질문을 여러 번 보았고 받아 들여지는 대답은 여전히 나를 혼란스럽게합니다. 많은 생각 끝에이 질문이 더 명확해질 수 있다고 생각합니다.
비교해보세요.
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
vs
public interface Constants {
double PI = 3.14159;
double PLANCK_CONSTANT = 6.62606896e-34;
}
같은 사용법. 훨씬 적은 코드.
@Pascal Thivent의 답변에 잘못된 강조가 있다고 생각합니다. 여기에 내 버전이 있습니다.
정적 멤버를 인터페이스에 넣고 해당 인터페이스 를 구현하는 것은 나쁜 습관입니다.
Effective Java의 인용문에는 다른 사람들이 지속적인 인터페이스를 구현하고 있다는 가정이 있습니다.
과 같은 이름의 상수 인터페이스를 만들 때 Constants
누구도 구현해서는 안됩니다. (기술적으로 가능하지만 여기서 유일한 문제입니다)
표준 라이브러리는 디자인의 오용 가능성을 감당할 수 없으므로 거기에서 아무것도 볼 수 없습니다.
그러나 일반 개발자의 일상적인 프로젝트의 경우 상수 인터페이스를 사용하는 것이 훨씬 쉽습니다 static
. final
,,empty constructor
, 등, 그리고 어떤 나쁜 디자인의 문제가 발생하지 않습니다. 내가 생각할 수있는 유일한 단점은 여전히 "인터페이스"라는 이름이 있지만 그 이상은 없다는 것입니다.
결국 나는 모든 사람들이 책을 인용하고 그들의 입장에 대한 의견과 정당성을 부여한다고 생각합니다. 나를위한 예외는 없습니다. 결정은 여전히 각 프로젝트의 개발자에게 달려 있습니다. 당신이 편안하다고 느끼면 계속 사용하십시오. 우리가 할 수있는 최선 은 프로젝트 전체에서 일관성을 유지하는 것 입니다.
public
인터페이스이기 때문에 생략 할 수도 있습니다. 간단히 double PI = 3.14159;
Usage of Constants.PI
는 Constants
인터페이스 를 구현하기 위해 이것을 사용하는 클래스가 필요하지 않습니다 ! 인터페이스 접근 방식은 사용 측면에서 훨씬 더 깔끔하다고 생각합니다. IMHO
Joshua Bloch, "Effective Java-Programming Language Guide":
상수 인터페이스 패턴은 인터페이스를 제대로 사용하지 않는 것입니다. 클래스가 내부적으로 일부 상수를 사용한다는 것은 구현 세부 사항입니다. 상수 인터페이스를 구현하면이 구현 세부 사항이 클래스의 내 보낸 API로 유출됩니다. 클래스가 상수 인터페이스를 구현하는 것은 클래스 사용자에게 중요하지 않습니다. 사실, 혼란 스러울 수도 있습니다. 더 나쁜 것은 약속을 나타냅니다. 향후 릴리스에서 더 이상 상수를 사용할 필요가 없도록 클래스가 수정되는 경우에도 이진 호환성을 보장하기 위해 인터페이스를 구현해야합니다. 최종 클래스가 아닌 클래스가 상수 인터페이스를 구현하는 경우 모든 하위 클래스는 인터페이스의 상수에 의해 네임 스페이스가 오염됩니다.
인터페이스를 구현하는 클래스에서 사용될 공통 상수가있는 경우 유용합니다.
예 : http://www.javapractices.com/topic/TopicAction.do?Id=32
그러나 권장되는 방법은 인터페이스에서 상수 대신 정적 가져 오기를 사용하는 것입니다. 다음은 참조입니다. http://www.javapractices.com/topic/TopicAction.do?Id=195
인터페이스에 대한 두 가지 사항 :
인터페이스는 이 를 구현 하는 객체 가 수행 할 수있는 작업 의 하위 집합 을 설명 합니다 . (이것이 직감입니다)
인터페이스는이 를 구현하는 객체 가 따르는 공통 상수를 설명 합니다.
따라서 Constants Interface 가 전역 상수에 사용되지 않으면 허용됩니다.
implements
합니다 (물론 구현시 이러한 공통 상수를 사용합니다).예:
interface Drawable {
double GOLDEN_RATIO = 1.618033988;
double PI = 3.141592653;
...
// methods
...
}
public class Circle implements Drawable {
...
public double getCircumference() {
return 2 * PI * r;
}
}
void usage() {
Circle circle = new Circle(radius: 3.0);
double maxRadius = 5.0;
if ( circle.getCircumference() < 2 * Circle.PI * maxRadius ) {
...
}
}
이 예에서 :
Circle implements Drawable
, 당신은 바로 그 아는 Circle
아마에 정의 된 상수에 따른다 Drawable
그렇지 않으면 좋은 것들 때문에 더 나쁜 이름을 선택해야 PI
하고 GOLDEN_RATIO
이미 촬영되었습니다!Drawable
오브젝트는 특정을 준수 PI
하고 GOLDEN_RATIO
정의 Drawable
없는,있을 수있는 개체 Drawable
파이와 황금 비율의 다른 정밀.javax.swing.SwingConstants
인터페이스 스윙 클래스 중 사용되는 정적 필드를 가지고 예이다. 이렇게하면 다음과 같은 것을 쉽게 사용할 수 있습니다.
this.add(LINE_START, swingcomponent);
this.add(this.LINE_START, swingcomponent);
또는 this.add(SwingComponents.LINE_START, swingcomponent);
그러나이 인터페이스에는 메소드가 없습니다 ...
나는이 질문을 보았고 언급되지 않은 것을 추가 할 것이라고 생각했습니다. 일반적으로, 나는 파스칼의 대답에 동의 여기 . 그러나 저는 인터페이스의 상수가 "항상"반 패턴이라고 생각하지 않습니다.
예를 들어 정의하는 상수가 해당 인터페이스에 대한 계약의 일부인 경우 인터페이스가 상수를위한 좋은 장소라고 생각합니다. 어떤 경우에는 구현 사용자에게 계약을 노출하지 않고 매개 변수를 비공개로 검증하는 것이 적절하지 않습니다. 공개 계약이 없으면 사용자는 클래스를 디 컴파일하고 코드를 읽는 것없이 유효성 검사를 추측 할 수 있습니다.
따라서 인터페이스를 구현하고 인터페이스에 계약을 보장하는 데 사용하는 상수 (예 : 정수 범위)가있는 경우 클래스 사용자는 인터페이스의 상수를 확인하여 인터페이스 인스턴스를 올바르게 사용하고 있는지 확인할 수 있습니다. 그들 자신. 상수가 구현에 전용이거나 구현이 패키지 전용이거나 다른 경우 불가능합니다.
클래스 간 공유 상수를 다룰 때 인터페이스 상수를 사용합니다.
public interface TestConstants
{
String RootLevelConstant1 = "RootLevelConstant1";
interface SubGroup1
{
String SubGroupConstant1 = "SubGroup1Constant1";
String SubGroupConstant2 = "SubGroup1Constant2";
}
interface SubGroup2
{
String SubGroupConstant1 = "SubGroup2Constant1";
String SubGroupConstant2 = "SubGroup2Constant2";
}
}
그룹화는 특히 큰 상수 세트가있는 거대한 자산입니다.
사용하려면 간단히 연결하면됩니다.
System.out.println(TestConstants.SubGroup1.SubGroupConstant1);
System.out.println(TestConstants.SubGroup2.SubGroupConstant1);
System.out.println(TestConstants.RootLevelConstant1);
필드는 공유하기 쉽고 추가 커플 링없이 참조 할 수 있도록 인터페이스에서 선언되어야합니다.
출처 : Java 개발자 도구 코딩 스타일