인터페이스는 아래 용도로만 사용해야 한다!
타입을 정의하는 것. 즉, 즉 인터페이스를 구현한 클래스는 자신의 인스턴스로 무엇을 할 수 있는지 인터페이스를 통해 클라이언트에게 알릴 수 있다.
상수 인터페이스란 메서드 없이 static final 필드로만 가득 찬 인터페이스이다.
public interface PhysicalConstants {
// 아보가드로 수
static final double AVOGADROS_NUMBER = 6.022_140_857e23;
// 볼츠만 상수
static final double BOLTZMANN_CONSTANT = 1.380_648_52e23;
// 전자 질량
static final double ELECTRON_MASS = 9.109_383_56e-31;
}
상수 인터페이스는 아래와 같은 문제점이 있다.
- 클래스 내부에서 사용하는 상수는 인터페이스가 아니라 내부 구현에 해당한다.
- 상수 인터페이스를 구현한 하위의 모든 클래스가 상수 인터페이스의 모든 값에 접근할 수 있다. 이는 내부 구현을 외부에 노출하는 것이다.
- final이 아닌 클래스가 상수 인터페이스를 구현한다면 모든 하위 클래스의 이름 공간이 그 인터페이스가 정의한 상수들로 오염되어 버린다.
- 아래 코드를 보자.
public interface Constants { int VALUE = 10; } public class MyBaseClass implements Constants { // 클래스 내부 구현 } public class MySubClass extends MyBaseClass { // 클래스 내부 구현 }
- MyBaseClass가 final이 아니라면 MySubClass가 VALUE를 사용할 수 있게 된다. MySubClass는 VALUE를 사용하지 않아도 되는 상황인데, 이름 공간에 VALUE라는 상수 값이 존재하게 된다.
- 아래 코드를 보자.
- 특정 클래스나 인터페이스와 강하게 연관된 상수라면 그 클래스나 인터페이스 자체에 추가하자. (위 코드 처럼 상수 인터페이스에 모아두지 말자!)
- ex. Integer 클래스의 MIN_VALUE, MAX_VALUE;
- 열거 타입으로 나타내기 적합한 상수라면 열거 타입으로 만들자.
- 인스턴스화 할 수 없는 유틸리티 클래스에 담아 공개하자.(상수 유틸리티 클래스)
- 아래 코드는 상수 인터페이스를 상수 유틸리티 클래스로 만든 예이다.
public class PhysicalConstants { private PhysicalConstants() {} // 객체를 생성시키 않도록 함 // 아보가드로 수 static final double AVOGADROS_NUMBER = 6.022_140_857e23; // 볼츠만 상수 static final double BOLTZMANN_CONSTANT = 1.380_648_52e23; // 전자 질량 static final double ELECTRON_MASS = 9.109_383_56e-31; }
- 아래 코드는 상수 인터페이스를 상수 유틸리티 클래스로 만든 예이다.
인터페이스는 타입을 정의하는 용도로만 사용하자. 상수 공개용 수단으로 사용하지 말자!