리팩토링 4탄(Enum)

Moon·2024년 2월 29일
0
  • Enum이란?
  • Enum이 등장하기 전
  • Enum은 왜 등장했을까?
  • Enum의 참조 방식
  • Enum을 잘 사용하는 방법(feat.이펙티브자바)
  • Enum은 언제 사용해야 하는가?
  • Enum 핵심 정리

  1. Enum이란?
  • Enum은 쉽게 이야기하면, 하나의 자료형이다. 열거하는 방식을 통해 멤버들의 집합을 보여준다.
  • Enum을 사용하게 되는 경우는 데이터(보통 한정된 데이터 묶음)를 관리하기 위해 사용한다.
    프로그래밍을 하다 보면 코드의 가독성과 유지 보수성을 향상시키 위한 상태 코드를 마주친다.
    예를 들어, 과일을 판매하는 마트는 APPLE = 1, BANANA = 2 와 같은 방식으로 관리한다.

  1. Enum이 등장하기 전
  • 자바5 이전까지는 final을 활용한 정수 열거 패턴을 사용하여 코드를 관리하였다
  • 정수 열거 패턴은 다음 3가지 문제를 갖는다.
    1) 타입 안전(type safe)을 보장하지 않는다
    2) 가독성이 좋지 않다
    3) 주문접수(10)를 건네야 할 메서드에 배달접수(10)를 보내고 동등 연산자(==)로 비교하더라도 컴파일러는 아무런 경고도 하지 않는다.
public static final int ORDER_ACCEPT = 10;         // 주문접수
public static final int ORDER_COMPLETE = 20;     // 주문완료
public static final int ORDER_CANCEL = 30;        // 주문취소

public static final int DELIVERY_ACCEPT = 10;         // 배달접수
public static final int DELIVERY_COMPLETE = 20;     // 배달완료
public static final int DELIVERY_CANCEL = 30;        // 배달취소

  1. Enum의 등장
  • Enum은 이런 단점들을 깨끗히 씻어 주었다
  • 다음은 가장 단순한 열거 타입이다
public enum Order {Accept, Complete, Cancel}
public enum Delivery {Accept, Complete, Cancel}
  • Enum은 다른 언어의 열거 타입과 비슷하지만, 자바의 Enum은 완전한 형태의 클래스
  • 상수 하나당 자신의 인스턴스를 하나씩 만들어 public static final 필드로 공개한다
  • 밖에서 접근할 수 있는 생성자를 제공하지 않기 때문에 final이다
    => 즉, 클라이언트는 인스턴스를 직접 생성하거나 확장할 수 없으니 인스턴스는 딱 하나씩만 존재한다.

  1. Enum의 참조 방식
  • 앞서 이야기 했듯이, Enum은 하나의 클래스다. 그렇기 때문에, reference 타입으로 분류되며, enum 상수값은 힙 영역에 저장된다.
  • enum 타입 변수 끼리 상수 데이터를 바라보기 때문에, 주소를 비교하는 == 연산은 true가 된다.
  • 아래 코드를 살펴보면, 스택 영역에 존재하는 order1, order2는 모두 메서드 영역에 존재하는 Accept의 주소를 복사한다. 해당 주소가 참조하는 힙 영역에서 Order객체를 찾을 수 있다.
public enum Order {Accept, Complete, Cancel}

public static void main(String[] args) {
	Order order1 = null;
    Order order2 = null;
    order1 = Order.Accept;
    order2 = Order.Accept;

    System.out.println("order1 == Order.Accept : " + (order1 == Order.Accept));
    System.out.println("order1 == order2 : " + (order1 == order2));
}

(결과)는 역시 모두 true다

order1 == Order.Accept : true
order1 == order2 : true


  1. Enum을 잘 사용하는 방법
  • 전략 열거 패턴을 활용하여, 코드의 유지보수성과 가독성 모두를 높힐 수 있다
  • switch문 보다 복잡하지만 더 안전하고 유연하다


public class GoodEnum {

    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);
        }

        // 전략 열거 타입
        enum PayType{
            WEEKDAY{
                int overtimePay(int minsWorked, int payRate){
                    return minsWorked <= MINS_PER_SHIFT ? 0
                            : (minsWorked - MINS_PER_SHIFT) * payRate / 2;
                }
            },

            WEEKEND{
                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);
            }
        }

    }
}
  • 해당 ENUM을 이용해 임금을 계산해볼 수 있다
    public static void main(String[] args) {
        // Example 1: Calculate pay for a weekday
        int weekdayPay = PayrollDay.MONDAY.pay(9 * 60, 10); // Worked 9 hours, $10 per hour
        System.out.println("Weekday Pay: $" + weekdayPay);

        // Example 2: Calculate pay for a weekend
        int weekendPay = PayrollDay.SATURDAY.pay(6 * 60, 12); // Worked 6 hours, $12 per hour
        System.out.println("Weekend Pay: $" + weekendPay);
    }

Weekday Pay: $1620000
Weekend Pay: $9331200


  1. Enum은 언제 사용해야 하는가? (feat.이펙티브 자바)
  • 필요한 원소를 컴파일 타임에 다 알 수 있는 상수 집합
    예) 태양계 행성, 한 주의 요일 등
  • 정의된 상수 개수가 고정 불변일 필요가 없는 집합
    예) 연산 코드, 메뉴아이템 등

  1. Enum 핵심정리
    (1) 열거 타입은 정수 상수보다 뛰어나다
    (2) 가독성이 높고 안전하다
    (3) 각 상수를 특정 데이터와 연결 짓거나 상수마다 다르게 동작하게 할 수 있다
    (4) 드물게는 하나의 메서드가 상수별로 다르게 동작할 수 있다 -> 이런 열거 타입은 switch문 대신 상수별 메서드를 구현하자.
    (5) 열거 타입 상수 일부가 같은 동작을 공유한다면, 전략 열거 타입 패턴을 사용하자
profile
안녕하세요. Moon입니다!

0개의 댓글