Item 38 : 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라
2021. 8. 6. 09:33
타입 안전 열거 패턴은 확장할 수 있으나 열거 타입은 그럴수 없다.
그러나 사실 대부분 상황에서 열거타입을 확장하는건 좋지 않은 생각이다.
그런데 확장할 수 있는 열거 타입이 어울리는 쓰임이 최소한 하나는 있다.
바로 연산코드(operation code 혹은 opcode)다.
이따금 API가 제공하는 기본 연산 외에 사용자 확장 연산을 추가할 수 있도록 열어줘야 할 때가 있다.
이 상황을 열거타입을 사용해 인터페이스 처럼 적용해보자
public interface Operation {
double apply(double x, double y);
}
public enum BasicOperation implements Operation {
PLUS("+") {
public double apply(double x, double y) { return x + y; }
},
MINUS("-") {
public double apply(double x, double y) { return x - y; }
},
TIMES("*") {
public double apply(double x, double y) { return x * y; }
},
DIVIDE("/") {
public double apply(double x, double y) { return x / y; }
};
private final String symbol;
BasicOperation(String symbol) {
this.symbol = symbol;
}
@Override public String toString() {
return symbol;
}
}
열거 타입인 BasicOperation은 확장할 수 없지만 인터페이스인 Operation은 확장할 수 있고,
이 인터페이스를 연산의 타입으로 사용하면 된다.
인터페이스를 활용해 지수 연산(EXP)과 나머지 연산(%)을 추가해보자.
public enum ExtendedOperation implements Operation {
EXP("^") {
public double apply(double x, double y) {
return Math.pow(x, y);
}
},
REMAINDER("%") {
public double apply(double x, double y) {
return x % y;
}
};
private final String symbol;
ExtendedOperation(String symbol) {
this.symbol = symbol;
}
@Override public String toString() {
return symbol;
}
}
apply를 Operation에 선언되어 있으니 열거타입에 따로 추상 메소드로 선언하지 않아도 된다.
한정적 와일드카드를 이용해 활용하는 방법을 봐보자
private static void test(Collection<? extends Operation> opSet,
double x, double y) {
for (Operation op : opSet)
System.out.printf("%f %s %f = %f%n",
x, op, y, op.apply(x, y));
}
인터페이스를 이용해 확장 가능한 열거 타입을 흉내 내는 방식에도 한가지 사소한 문제가 있다.
바로 열거 타입끼리 구현을 상속할 수 없다는 점이다.
Operation 예시처럼 BasicOperation과 ExtendedOperation 모두에 연산기호를 저장하고 찾는 로직이 들어가야 한다.
'책 > 이펙티브자바' 카테고리의 다른 글
Item 40 : @Override 어노테이션을 일관되게 사용하라 (0) | 2021.08.09 |
---|---|
Item 39 : 명명 패턴보다 어노테이션을 사용하라 (0) | 2021.08.07 |
Item 37 : ordinal 인덱싱 대신 EnumMap을 사용하라 (0) | 2021.08.05 |
Item 36 : 비트 필드 대신 EnumSet을 사용하라 (0) | 2021.08.05 |
Item 35 : ordinal 메소드 대신 인스턴스 필드를 사용하라 (0) | 2021.08.03 |