인터페이스는 타입을 정의하는 용도로만 사용해야한다. 상수 공개용 수단으로 사용하지 말자.
인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다.
클래스가 어떤 인터페이스를 구현한다는건, 인스턴스로 무엇을 할 수 있는지를 클라이언트를 알려주는 행위
안티패턴 - 사용 금지
메서드 없이, 상수를 뜻하는 static final 필드로만 가득찬 인터페이스
1
2
3
4
5
6
7
8
public interface PhysicalConstants {
// 아보가드로 수
static final double AVOGADROS_NUMBER = 6.022_140_857e23;
// 볼츠만 상수
static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23;
// 전자 질량
static final double ELECTRON_MASS = 9.109_383_56e-31;
}
문제점
- 클래스 내부에서 사용하는 상수는 외부 인터페이스가 아닌 내부 구현이다.
- 내부 구현을 클래스의 API로 노출하는 행위가 됨.
1 2
// 인터페이스에서 protected도 불가!! : 제어자 'protected'은(는) 허용되지 않습니다 protected static final double AVOGADROS_NUMBER = 6.002_140_857e23;
- 내부 구현을 클래스의 API로 노출하는 행위가 됨.
- 사용자에게 혼란을 줌.
- 사용자에게는 아무런 의미가 없다.
- 다음 릴리즈에 사용하지 않더라도 바이너리 호환성을 위해 여전히 상수 인터페이스를 구현하고 있어야 한다.
- 다음 릴리즈에 call에서 AVOGADROS_NUMBER를 사용하고 있지 않더라도 삭제하면 main의 myResult 할당부에서 에러 발생
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Calculator implements PhysicalConstants {
public double call(int input){
return input * AVOGADROS_NUMBER;
}
public double call2(int input){
return input * BOLTZMANN_CONSTANT;
}
public double call3(int input){
return input * ELECTRON_MASS;
}
public static void main(String[] args) {
Calculator calculator = new Calculator();
double myResult = 100 * Calculator.AVOGADROS_NUMBER;
System.out.println(myResult);
}
}
- final이 아닌 클래스가 상수 인터페이스를 구현한다면 모든 하위 클래스의 이름공간이 그 인터페이스가 정의한 상수들로 오염되어 버린다.
대안
상수를 공개할 목적이라면 몇 가지 대안이 있다.
1. 클래스나 인터페이스 자체에 추가
ex) Integer와 Double에 선언된 MIN_VALUE와 MAX_VALUE 상수
1
2
3
4
public final class Integer extends Number implements Comparable<Integer>, Constable, ConstantDesc {
@Native public static final int MIN_VALUE = 0x80000000;
@Native public static final int MAX_VALUE = 0x7fffffff;
}
2. 상수 유틸리티 클래스 제공
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class PhysicalConstants {
//인스턴스화 방지
private PhysicalConstants(){}
// 아보가드로 수
static final double AVOGADROS_NUMBER = 6.022_140_857e23;
// 볼츠만 상수
static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23;
// 전자 질량
static final double ELECTRON_MASS = 9.109_383_56e-31;
}
public class Calculator{
public double call(int input){
return input * PhysicalConstants.AVOGADROS_NUMBER;
}
public double call2(int input){
return input * PhysicalConstants.BOLTZMANN_CONSTANT;
}
public double call3(int input){
return input * PhysicalConstants.ELECTRON_MASS;
}
public static void main(String[] args) {
Calculator calculator = new Calculator();
double myResult = 100 * PhysicalConstants.AVOGADROS_NUMBER;
System.out.println(myResult);
}
}
3. enum 활용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public enum PhysicalConstants {
AVOGADROS_NUMBER(6.022_140_857e23),
BOLTZMANN_CONSTANT(1.380_648_52e-23),
ELECTRON_MASS(9.109_383_56e-31);
private double value;
PhysicalConstants(double value) {
this.value = value;
}
public double getValue(){
return value;
}
}
public class Calculator{
public double call(int input){
return input * PhysicalConstants.AVOGADROS_NUMBER.getValue();
}
public double call2(int input){
return input * PhysicalConstants.BOLTZMANN_CONSTANT.getValue();
}
public double call3(int input){
return input * PhysicalConstants.ELECTRON_MASS.getValue();
}
public static void main(String[] args) {
Calculator calculator = new Calculator();
double myResult = 100 * PhysicalConstants.AVOGADROS_NUMBER.getValue();
System.out.println(myResult);
}
}