public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;
얘는..얘는..!! 더 나쁘다..!!😭
이런 열거 패턴의 단점을 말끔히 씻어주는..
public enum Apple { FUJI, PIPPIN, GRANNY_SMITH }
완전한 클래스이다
상수 하나당 (위 Apple 열거 클래스는 3개의 상수를 갖는다) 자신의 인스턴스를 하나씩 만들어 public static final
필드로 공개
(enum의 생성자는 private만 허용) 사실상 final 클래스임 -> 인스턴스들은 딱 하나씩만 존재 보장 => 인스턴스 통제된다.
타입 안전성 제공
열거 타입에는 각자의 이름공간이 있어서 이름이 같은 상수 공존 가능 (두개의 다른 열거타입에서 같은 이름의 상수가 존재해도 된다는 의미인듯?)
toString 메서드는 열거 타입의 적절한 문자열을 내어줌
임의의 메서드나 필드 추가 가능
public enum Planet {
MERCURY(3.302e+23, 2.439e6),
VENUS (4.869e+24, 6.052e6),
..길어서 생략
private final double mass; // 질량(단위: 킬로그램)
private final double radius; // 반지름(단위: 미터)
private final double surfaceGravity; // 표면중력(단위: m / s^2)
// 중력상수(단위: m^3 / kg s^2)
private static final double G = 6.67300E-11;
// 생성자자에서 데이터(mass, radius)를 받아
Planet(double mass, double radius) {
//인스턴스 필드에 저장
this.mass = mass;
this.radius = radius;
//아래는 단순히 코드 최적화를 위함임
surfaceGravity = G * mass / (radius * radius);
}
Planet.values()
: Planet 열거 타입 안에 정의된 상수들의 값을 배열에 담아 반환하는 정적 메서드 toString()
을 오버라이딩하면 원하는 문자열 출력 가능//연산자 열거 타입 클래스
public enum Operation {
PLUS("+") {
public double apply(double x, double y) { return x + y; }
},
MINUS("-") {
public double apply(double x, double y) { return x - y; }
};
private final String symbol;
//생성자에서 symbol 받아서 넣어줌
Operation(String symbol) { this.symbol = symbol; }
//해당 상수 출력시 +나 -같은 문자열이 나오게 할 수 있다.
@Override public String toString() { return symbol; }
// 추상 메서드인 apply를 선언하여 상수가 추가되면 무조건 apply로 구현하게끔 한다.
public abstract double apply(double x, double y);
}
모든 상수에 중복해서 넣거나 필요한 메서드를 적절히 호출하게 한다면 가독성도 크게 떨어지고 오류 발생 가능성이 높아진다.
package effectivejava.chapter6.item34;
import static effectivejava.chapter6.item34.PayrollDay.PayType.*;
// 코드 34-9 전략 열거 타입 패턴 (218-219쪽)
enum PayrollDay {
//WEEKDAY | WEEKEND 는 잔업수당을 계산하는 PayType 전략 열거타입의 인스턴스
//PayrollDay 생성자에서 이중 적당한 것을 선택
MONDAY(WEEKDAY), TUESDAY(WEEKDAY), WEDNESDAY(WEEKDAY), THURSDAY(WEEKDAY), FRIDAY(WEEKDAY),
SATURDAY(WEEKEND), SUNDAY(WEEKEND);
//사용하게 될 수당 타입
private final PayType payType;
//PayrollDay 생성자에서 잔업수당 set
PayrollDay(PayType payType) { this.payType = payType; }
int pay(int minutesWorked, int payRate) { //수당 함수
//PayrollData 생성시 넣어준 전략 타입에 의해서 수당이 구해짐
//switch 나 상수별 메서드 구현(apply)가 필요 없어짐 -> 복잡하지만 더 안전하고 유연함
return payType.pay(minutesWorked, payRate);
}
// PayrollDay 열거 타입 내부에 선언된 PayType 전략 열거 타입
enum PayType {
WEEKDAY {
int overtimePay(int minsWorked, int payRate) {
//주간 추가 근무수당 : 8시간보다 이상으로 일한 경우 더 일한 시간 만큼의 절반
return minsWorked <= MINS_PER_SHIFT ? 0 :
(minsWorked - MINS_PER_SHIFT) * payRate / 2;
}
},
WEEKEND {
int overtimePay(int minsWorked, int payRate) {
//주말 추가 근무수당 : 기본수당의 절반 더 가져!
return minsWorked * payRate / 2;
}
};
//상수별로 추가근무 수당 기준을 다르게 하도록 추상함수 추가
abstract int overtimePay(int mins, int payRate);
private static final int MINS_PER_SHIFT = 8 * 60; //8시간
//수당 반환 함수
int pay(int minsWorked, int payRate) {
int basePay = minsWorked * payRate;
//기본수당 + 추가수당
return basePay + overtimePay(minsWorked, payRate);
}
}
public static void main(String[] args) {
for (PayrollDay day : values())
System.out.printf("%-10s%d%n", day, day.pay(8 * 60, 1));
}
}