문자열에 따른 특정 조건이 있을 때
단순히 문자열을 조건문으로 구분하여 코드를 실행한다면
오타가 발생하기 쉽고, 유효하지 않은 값이 입력될 수 있다
또한 코드 복잡도도 증가한다
대안으로 문자열 상수 값으로 갖는 객체를 사용할 수 있다
보기에는 좋지만 위 문제를 근본적으로 해결할 수는 없다
매개변수에서 해당 객체 내의 값이 아닌 String 을 입력한다면
역시나 위 문제는 그대로 발생한다
위 문제를 해결하기 위해 오랜기간 고민 후 나온 결과가
타입 안전 열거형 패턴이다
public class Grade {
public static final Grade BASIC = new Grade();
public static final Grade GOLD = new Grade();
public static final Grade DIAMOND = new Grade();
}
public class DiscountService {
public int discount(Grade grade, int price) {
int discountPercent = 0;
if (grade == Grade.BASIC) {
// basic
} else if (grade == Grade.GOLD) {
// gold
} else if (grade == Grade.DIAMOND) {
// diamon
} else {
System.out.println('x')
}
}
return price * discountPercent / 100;
}
이렇게 하더라도 Grade 인스턴스를 새로 생성해서 인자로 주게될 경우
앞선 문제가 발생할 수 있기 때문에
Grade 의 생성자를 private 으로 설정하여
외부에서 인스턴스를 생성할 수 없도록 한다
public class Grade {
public static final Grade BASIC = new Grade();
public static final Grade GOLD = new Grade();
public static final Grade DIAMOND = new Grade();
private Grade() {} // private 생성자 추가
}
타입 안전 열거형 패턴을 구현하기 위해 코드량이 많아지고
private 생성자를 추가하는 등 유의해야 하는 부분들이 있다
타입 안전 열거형 패턴을 쉽게 작성할 수 있도록
Enum Type 을 지원한다
열거형은 상수들의 집합을 정의하는 것을 의미하며
프로그래밍에서는 이러한 상수들을 사용해 코드 내 미리 정의된 값들의 집합을 나타낸다
public enum Grade {
BASIC, GOLD, DIAMOND
}
열거형 정의 시에는 enum 을 사용하여
원하는 상수들의 이름을 나열하면 된다
위 코드는 타입 안전 열거형 패턴의 class 와 같은 기능을 한다
public class Grade {
public static final Grade BASIC = new Grade();
public static final Grade GOLD = new Grade();
public static final Grade DIAMOND = new Grade();
private Grade() {} // private 생성자 추가
}
enum 을 사용하면 class 를 사용해
각 상수의 인스턴스를 생성하는 것과 정확히 동일한 결과를 가져온다
열거형은 toString() 이 자신의 이름을 참조하도록 오버라이딩 되어있기 때문에
따로 함수를 만들어 확인 가능하다
System.out.println(Grade.BASIC.getClass());
System.out.println(refValue(Grade.BASIC));
private static String refValue(Object grade) {
return Integer.toHexString(System.identityHashCode(grade));
}
열거형을 switch 문에서 사용할 수 있다
열거형을 사용하는 경우 static import 를 사용하여 간결한 코드를 만들 수 있다
-> 상수이기 때문에 가능
모든 열거형은 java.lang.Enum 클래스를 상속받는다
Grade[] values = Grade.values(); // 모든 ENUM 반환
for (Grade value: values) {
System.out.println(value.name());
}
// String -> ENUM 변환 (이미 정의된 ENUM 상수에 대해서만 가능)
String input = "GOLD";
Grade gold = Grade.valueOf(input);
ENUM 의 ordinal() 메서드는 사용하지 않는다
ordinal() 사용 중간에 상수 선언 위치가 변경되면
전체 상수 위치가 변경될 수 있다
열거형은 각 상수의 값을 순서대로
0, 1, 2.. 등으로 로 저장하기 때문에
상수 선언이 중간에 추가될 경우
기존에 사용하던 상수의 값이 변경되어도
정상적으로 실행된다
따라서 기존 코드의 모든 값이 다른 것으로 변경된다
public enum Grade {
BASIC(10), GOLD(20), DIAMOND(30); // 생성자 호출
private final int discountPercent;
Grade(int discountPercent) { // 생성자
this.discountPercent = discountPercent;
}
// 열거형도 클래스이므로 메서드 추가 가능
public int getDiscountPercent() {
return discountPercent;
}
public int discount(int price) {
return price * discountPercent / 100;
}
}