Item 34. Enum

int μƒμˆ˜ λŒ€μ‹  μ—΄κ±° νƒ€μž…μ„ μ‚¬μš©ν•˜λΌ.

μ—΄κ±° νƒ€μž…μ€ 일정 개수의 μƒμˆ˜ 값을 μ •μ˜ν•˜μ—¬ κ·Έ μ™Έμ˜ 값은 ν—ˆμš©ν•˜μ§€ μ•ŠλŠ” νƒ€μž…μœΌλ‘œ, 정해진 κ°’λ§Œμ„ μ‚¬μš©ν•˜κ³  싢을 λ•Œ μ‚¬μš©ν•œλ‹€. μ—΄κ±° νƒ€μž… 지원 μ΄μ „μ—λŠ” μ •μˆ˜ μƒμˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„ν•˜μ˜€μ§€λ§Œ νƒ€μž… μ•ˆμ „μ„ 보μž₯ν•˜μ§€ μ•Šκ³  가독성도 쒋지 μ•Šμ•˜λ‹€.

μ—΄κ±° νƒ€μž…

μ—΄κ±° νƒ€μž…μ€ λ‹€μŒκ³Ό 같이 μ •μ˜ν•  수 μžˆλ‹€.

public enum Apple {
    FUJI, PIPPIN, GRANNY_SMITH
}

C/C++의 enumκ³Ό 달리 μ—΄κ±° νƒ€μž…μ€ μ™„μ „ν•œ ν˜•νƒœμ˜ 클래슀기 λ•Œλ¬Έμ— λ‹€λ₯Έ μ–Έμ–΄μ˜ μ—΄κ±° νƒ€μž…λ³΄λ‹€ ν•  수 μžˆλŠ” 일이 λ§Žλ‹€. μ—΄κ±° νƒ€μž… μžμ²΄κ°€ 클래슀이기 λ•Œλ¬Έμ—, μƒμˆ˜ ν•˜λ‚˜λ‹Ή μžμ‹ μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό ν•˜λ‚˜μ”© λ§Œλ“€μ–΄ public static final ν•„λ“œλ‘œ κ³΅κ°œλ˜λŠ” 것이닀. 그에 따라 μƒκΈ°λŠ” νŠΉμ§•μ€ λ‹€μŒκ³Ό κ°™λ‹€.

  • λ°–μ—μ„œ μ ‘κ·Όν•  수 μžˆλŠ” μƒμ„±μžλ₯Ό μ œκ³΅ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό 직접 생성할 수 μ—†μŒ

  • 직접 μƒμ„±ν•˜κ±°λ‚˜ ν™•μž₯ λΆˆκ°€λŠ₯ν•˜λ―€λ‘œ μΈμŠ€ν„΄μŠ€λ“€μ€ 미리 μ •μ˜λœ μƒμˆ˜ ν•˜λ‚˜ μ”©λ§Œ μ‘΄μž¬ν•¨(싱글턴을 μΌλ°˜ν™”ν•œ ν˜•νƒœ)

미리 μ •μ˜λœ μƒμˆ˜λ§Œ μ‚¬μš©ν•  수 있기 λ•Œλ¬Έμ— μ»΄νŒŒμΌνƒ€μž„μ— λ‹€ μ•Œ 수 μžˆλŠ” μƒμˆ˜ 집합이라면 μ—΄κ±° νƒ€μž…μ„ μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.

λ©”μ„œλ“œμ™€ ν•„λ“œ μΆ”κ°€

κ²°κ΅­ μ™„μ „ν•œ ν˜•νƒœμ˜ 클래슀기 λ•Œλ¬Έμ— μ—΄κ±° νƒ€μž…μ€ λ‹€μŒκ³Ό 같이 λ©”μ„œλ“œμ™€ ν•„λ“œλ₯Ό μΆ”κ°€ν•  수 μžˆλ‹€.

enum Operation {
    PLUS("+") {
        @Override
        public double apply(double x, double y) {
            return x + y;
        }
    },
    MINUS("-") {
        @Override
        public double apply(double x, double y) {
            return x - y;
        }
    },
    TIMES("*") {
        @Override
        public double apply(double x, double y) {
            return x * y;
        }
    },
    DIVIDE("/") {
        @Override
        public double apply(double x, double y) {
            return x / y;
        }
    };

    private final String symbol;

    Operation(String symbol) {
        this.symbol = symbol;
    }

    // 좔상 λ©”μ„œλ“œλ‘œ 각 μƒμˆ˜μ—μ„œ λ‹€λ₯Έ λ™μž‘μ„ μˆ˜ν–‰ν•˜λ„λ‘ 함
    public abstract double apply(double x, double y);

    // 일반 λ©”μ„œλ“œλ‘œ ν•΄λ‹Ή μƒμˆ˜μ˜ ν•„λ“œλ₯Ό λ°˜ν™˜ν•˜λ„λ‘ 함
    public String getSymbol() {
        return symbol;
    }

    // static λ©”μ„œλ“œλ‘œ λ¬Έμžμ—΄μ„ λ°›μ•„ ν•΄λ‹Ή λ¬Έμžμ—΄μ„ κ°€μ§€λŠ” μƒμˆ˜λ₯Ό λ°˜ν™˜ν•˜λ„λ‘ 함
    public static Operation fromString(String symbol) {
        return Arrays.stream(values())
                .filter(op -> op.symbol.equals(symbol))
                .findFirst()
                .orElseThrow(IllegalArgumentException::new);
    }

    // toString λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•˜μ—¬ ν•΄λ‹Ή μƒμˆ˜μ˜ ν•„λ“œλ₯Ό λ°˜ν™˜ν•˜λ„λ‘ 함
    @Override
    public String toString() {
        return getSymbol();
    }
}

class Main {

    public static void main(String[] args) {
        double x = 10;
        double y = 5;
        for (Operation op : Operation.values()) {
            System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
        }
    }
}

μ „λž΅ μ—΄κ±° νƒ€μž… νŒ¨ν„΄(Strategy Enum Pattern)

μ—΄κ±° νƒ€μž…μ„ μ‚¬μš©ν•˜λ©΄ μƒμˆ˜λΌλ¦¬ μ½”λ“œλ₯Ό κ³΅μœ ν•˜κΈ° μ–΄λ ΅λ‹€λŠ” 단점이 μžˆλ‹€. μ•„λž˜ μ½”λ“œλŠ” 주쀑/주말에 따라 μž”μ—… μˆ˜λ‹Ήμ„ κ³„μ‚°ν•˜λŠ” μ½”λ“œμΈλ°, switch 문을 톡해 μž”μ—… μˆ˜λ‹Ήμ„ κ³„μ‚°ν•˜κ³  μžˆλ‹€. μš°μ„ μ€ κ°„κ²°ν•˜κ²Œ ν‘œν˜„λ˜λŠ” μ½”λ“œμ§€λ§Œ, 관리 κ΄€μ μ—μ„œλŠ” μœ„ν—˜ν•œ μ½”λ“œλ‘œ, νœ΄κ°€μ™€ 같은 μƒˆλ‘œμš΄ 값이 μΆ”κ°€λ˜λ©΄ switch 문을 μ°Ύμ•„ ν•΄λ‹Ή case 문을 μΆ”κ°€ν•΄μ•Ό ν•œλ‹€.

enum PayrollDay {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;

    private static final int MINS_PER_SHIFT = 8 * 60;

    int pay(int minutesWorked, int payRate) {
        int basePay = minutesWorked * payRate;

        int overtimePay;
        switch (this) {
            case SATURDAY:
            case SUNDAY:
                overtimePay = basePay / 2;
                break;
            default:
                overtimePay = minutesWorked <= MINS_PER_SHIFT ?
                        0 : (minutesWorked - MINS_PER_SHIFT) * payRate / 2;
        }

        return basePay + overtimePay;
    }
}

이λ₯Ό 보닀 μ •ν™•ν•˜κ³  μ•ˆμ •μ μœΌλ‘œ κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄μ„  두 가지 방법이 μ‘΄μž¬ν•˜λŠ”λ°, 두 방식 λͺ¨λ‘ 가독성이 떨어지고 μ½”λ“œκ°€ μž₯ν™©ν•΄μ§€λŠ” 단점이 μžˆλ‹€.

  1. μž”μ—… μˆ˜λ‹Ήμ„ κ³„μ‚°ν•˜λŠ” μ½”λ“œλ₯Ό λͺ¨λ“  μƒμˆ˜μ— μ€‘λ³΅ν•˜μ—¬ μž‘μ„±

  2. 계산 μ½”λ“œλ₯Ό 평일/주말용으둜 λ‚˜λˆ  각각 λ„μš°λ―Έ λ©”μ„œλ“œλ‘œ μž‘μ„±ν•œ λ’€ 각 μƒμˆ˜κ°€ μ•Œλ§žλŠ” λ©”μ„œλ“œ 호좜

μ΄λŸ¬ν•œ 방법이 μ•„λ‹Œ μƒμˆ˜λ₯Ό μΆ”κ°€ν•  λ•Œ μƒμ„±μžμ—μ„œ μ „λž΅μ„ μ„ νƒν•˜λ„λ‘ ν•˜μ—¬ ν•΄κ²°ν•  수 μžˆλ‹€.

enum PayrollDay {
    MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY),
    SATURDAY(PayType.WEEKEND), SUNDAY(PayType.WEEKEND);

    private final PayType payType;

    PayrollDay(PayType payType) {
        this.payType = payType;
    }

    int pay(int minutesWorked, int payRate) {
        return payType.pay(minutesWorked, payRate);
    }

    // μ „λž΅ μ—΄κ±° νƒ€μž…
    private enum PayType {
        WEEKDAY {
            @Override
            int overtimePay(int minsWorked, int payRate) {
                return minsWorked <= MINS_PER_SHIFT ? 0 : (minsWorked - MINS_PER_SHIFT) * payRate / 2;
            }
        },
        WEEKEND {
            @Override
            int overtimePay(int minsWorked, int payRate) {
                return minsWorked * payRate / 2;
            }
        };

        private static final int MINS_PER_SHIFT = 8 * 60;

        abstract int overtimePay(int mins, int payRate);

        int pay(int minsWorked, int payRate) {
            int basePay = minsWorked * payRate;
            return basePay + overtimePay(minsWorked, payRate);
        }
    }
}

μ΄λ ‡κ²Œ ν•˜λ©΄ κΈ°μ‘΄ switch문보닀 μ½”λ“œ 양은 λ§Žμ•„μ§€μ§€λ§Œ, μƒˆλ‘œμš΄ μƒμˆ˜λ₯Ό μΆ”κ°€ν•  λ•Œλ§ˆλ‹€ switch문을 μ°Ύμ•„ case문을 μΆ”κ°€ν•˜λŠ” 것보닀 훨씬 μ•ˆμ „ν•˜κ³  μœ μ—°ν•˜λ‹€. μ΄λŸ¬ν•œ 방법을 μ „λž΅ μ—΄κ±° νƒ€μž… νŒ¨ν„΄μ΄λΌ ν•˜λ©°, μ—΄κ°€ νƒ€μž… μƒμˆ˜ 일뢀가 같은 λ™μž‘μ„ κ³΅μœ ν•œλ‹€λ©΄ 이 방식을 μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.

Last updated

Was this helpful?