일반 int상수 패턴
public static final int APPLE_FUGI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
단점
· 형 안전성
int i = (APPLE_FUGI - ORANGE_NAVEL) / APPLE_PIPPIN;
· 깨지기 쉬운 프로그램
ㄴ int enum상수는 컴파일 시점 상수이기 때문에 상수를 사용하는 클라이언트 코드와 함께 컴파일된다.
ㄴ 상수의 int값이 변경되면 클라이언트도 다시 컴파일 해야한다.(컴파일이 안되면 결과를 예측할 수 없다.)
Enum 자료형
public enum Apple{PUJI,PIPPIN};
public enum Orange{NEVEL, TEMPLE};
· 각 열거 상수별로 하나의 객체를 public static final필드 형태로 제공
· 클라이언트에서 enum 자료형으로 새로운 객체를 생성하거나 계승할 수 없다.
· 싱글턴 패턴을 일반화 한것(규칙 3)
장점
· 컴파일 시점 형 안전성 제공
ㄴ Apple인자를 받을 때 엉뚱한 자료형 전달하면 컴파일 오류, ==해도 다른 자료형이면 같은 결과
· 같은 이름의 상수가 공존할 수 있다.
ㄴ 이름공간이 분리되어 있다.
· 상수를 추가하거나 순서를 변경해도 클라이언트는 다시 컴파일 할 필요가 없다.
ㄴ 상수를 제공하는 필드가 enum자료형과 클라이언트 사이에서 격리 계층 구실
· toString을 통해 인쇄가능 문자열로 변환 가능
· 임의의 메서드나 필드, 인터페이스를 추가할 수 있다.
Enum 자료형 활용법
· 자기 값에 따라 분기하는 Enum자료형
enum Operation{
PLUS, MINUS, TIMES, DIVIDE;
double apply(double x, double y) {
switch(this) {
case PLUS : return x + y;
case MINUS : return x - y;
case TIMES : return x * y;
case DIVIDE : return x / y;
}
throw new AssertionError("Unknown op : " + this);
}
}
swtich문이 다음까지 이어질 수 있기 때문에 throw문 없이는 컴파일 되지 않는다.
새로운 Enum타입을 추가 했을 때 case 또한 추가 해줘야하므로 좋은 코드가 아니다.
// 상수별로 메서드 구현을 이용한 enum자료형
enum Operation2{
PLUS {double apply(double x, double y){return x+y;};},
MINUS {double apply(double x, double y){return x-y;};},
TIMES {double apply(double x, double y){return x*y;};},
DIVIDE {double apply(double x, double y){return x/y;};};
abstract double apply(double x, double y);
}
상수별 메서드를 강제하여 apply의 구현을 잊지 않도록 한다.
// 상수별로 클래스 몸체와 데이터를 갖는 enum자료형
enum Operation3{
PLUS("+"){
double apply(double x, double y){return x+y;}
},
MINUS("-"){
double apply(double x, double y){return x-y;}
},
TIMES("*"){
double apply(double x, double y){return x*y;}
},
DIVIDE("/"){
double apply(double x, double y){return x/y;}
};
private final String symbol;
private Operation3(String symbol){this.symbol = symbol;};
@Override public String toString() {return symbol;}
abstract double apply(double x, double y);
//Enum자료형에 대한 fromString 메서드 구현
private static final Map<String, Operation3> stringToEnum = new HashMap<String, Operation3>();
static {
for (Operation3 op : values()) {
stringToEnum.put(op.toString(), op);
}
}
//문자열이 주어지면 그에대한 Operation 상수 반환, 잘못된 문자열이면 null반환
public static Operation3 fromString(String symbol) {
return stringToEnum.get(symbol);
}
}
상수별 데이터와 메서드 구현을 혼용하여 사용, Enum에서 toString을 재정의할 시 fromString메서드를 작성해서 toString이 뱉어내는 문자열을 다시 enum상수로 변환할 수단을 제공
// 정책 enum패턴
enum PayrollDay{
MONDAY(PayType.WEEKDAY),
WEDNESDAY(PayType.WEEKDAY),
FRIDAY(PayType.WEEKEND),
SUNDAY(PayType.WEEKEND);
private final PayType payType;
private PayrollDay(PayType payType) { this.payType = payType;}
double pay(double hoursWorked, double payRate) {
return payType.pay(hoursWorked, payRate);
}
//정책 자료형 enum자료형
private enum PayType{
WEEKDAY{
double overtimePay(double hours, double payRate) {
return hours <= HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT) * payRate / 2;
}
},
WEEKEND{
double overtimePay(double hours, double payRate) {
return hours * payRate / 2;
}
};
private static final int HOURS_PER_SHIFT = 8;
abstract double overtimePay(double hours, double payRate);
double pay(double hoursWorked, double payRate) {
double basePay = hoursWorked * payRate;
return basePay + overtimePay(hoursWorked, payRate);
}
}
}
결론
언제 Enum을 사용해야 하나?
· 고정된 상수 집합이 필요할 때
· 동일한 메서드가 상수별로 다르게 동작이 필요할 때 Swtich대신 Enum으로
· 여러 Enum 상수가 공통 기능을 이용해야 할때 정책 Enum패턴
'IT > Programming' 카테고리의 다른 글
<Effective Java> RULE 28 한정적 와일드카드를 써서 API 유연성을 높여라 (0) | 2023.04.27 |
---|---|
<Effective Java> RULE 29 형안전 다형성 컨테이너를 쓰면 어떨지 따져보라 (0) | 2023.04.27 |
<Effective Java> RULE 31 ordinal 대신 객체 필드를 사용하라 (0) | 2023.04.27 |
<Effective Java> RULE 32 비트필드 대신 EnumSet을 사용하라 (0) | 2023.04.27 |
<Effective Java> RULE 33 ordinal을 배열첨자로 사용하는 대신 EnumMap을 이용하라 (0) | 2023.04.27 |