enum 의 활용(1) - 상수에 value 추가

2022. 9. 19. 20:09Dev/Java

enum으로 할 수 있는 다양한 활용이 있는데  단순히 상수를 정의 하는 것만으로 끝내기에는 너무 아쉽다. 다양한 활용법 중에서 이 글에서는 가장 먼저 각 상수가 데이터-value를 가지도록 작성하는 방법과 이것이 활용적인 측면에서 가지는 이점에 대해서 알아보고자 한다.

 

Value 의 추가

하나의 상수에 하나의 값을 연관지어보자. 예를 들면 "월요일 점심은 도시락, "화요일 점심은 고구마"...

A이면 B의 가장 단순한 폼은 조건문(if-else / swith-case)일 것이다. 이를 코드로 보면

public String getLunchMenuByDayOfWeek(DayOfWeek dayOfWeek) {
        String menu;
        
        if (dayOfWeek == DayOfWeek.MONDAY) {
            menu = "도시락";
        } else if (dayOfWeek == DayOfWeek.TUESDAY) {
            menu = "고구마";
        /*
        ...
        else if 수,목,금,토,일 에 대한 추가 정의
        ...
         */
        } else {
            menu = "김밥천국";
        }
    
        return menu;
    }

이러한 코드가 잘못 되었다고 얘기하려는게 아니다. 다만 menu value 가 DayOfWeek 라는 enum 의 상수에 강력하게 묶여 있다면 묶여 있는 것들끼리 한곳에서 관리하도록 작성하는게 더 나은 방법이 될 것이다. 이를 enum 에서는 아래와 같이 작성할 수가 있다.

public enum DayOfWeek {
    MONDAY("도시락"),
    TUESDAY("고구마"),
    WEDNESDAY("도시락"),
    THURSDAY("햄버거"),
    FRIDAY("샐러드"),
    SATURDAY("햄버거"),
    SUNDAY("샐러드");
    
    private final String lunchMenu;
    
    DayOfWeek(String lunchMenu) {
        this.lunchMenu = lunchMenu;
    }
    
    public String getLunchMenu() {
        return lunchMenu;
    }
}

 

상수에 넣을 데이터의 형을 instant field 로 선언하고 enum상수에 전달될 문자열 lunchMenu는 immutable 이므로 final 로 선언한다.  선언한 field가 초기화 될 수 있도록 생성자를 작성하고, 마지막으로 상수에 해당하는 메뉴를 추출할 getter 를 만들어 준다. 이 중에서 final instant field와 생성자는 필수이고 getter는 옵션이다.(이 예제에서는 넣었지만 필요 없다면 작성하지 않아도 된다. 즉 다른 method 들을 추가할 수도 있다)

이제 "상수:점심메뉴"가 완벽하게 하나로 묶였다.

 

조금 더 확장해보자

public enum DayOfWeek {
    MONDAY("빵","도시락", "샐러드"),
    TUESDAY("빵","고구마", "고기"),
    WEDNESDAY("미역국", "도시락", "샐러드"),
    THURSDAY("샐러드", "햄버거", "카레"),
    FRIDAY("카레","샐러드", "고기"),
    SATURDAY(null, "햄버거", "피자"),
    SUNDAY(null, "샐러드", "치킨");
    
    private final String breakfastMenu;
    private final String lunchMenu;
    private final String dinnerMenu;
    
    DayOfWeek(String breakfastMenu, String lunchMenu, String dinnerMenu) {
        this.breakfastMenu = breakfastMenu;
        this.lunchMenu = lunchMenu;
        this.dinnerMenu = dinnerMenu;
    }
    
    // 이하 getter
    
}

위에서 예시로 든 if-else 문으로 위의 enum을 역으로 대체한다고 생각해보자. 얼마나 코드가 산만해질지 예상이 갈 것이다.(하나의 method로 아침/점심/저녁 메뉴 3개를 리턴받기 위해서는 리턴타입을 별도로 정의해줘야 하거나 아침/점심/저녁 메뉴를 리턴하는 3개의 method 를 작성해야 할 것이다)

 

이것과 닮아 있다?

이렇게 강력하게 상수와 묶여 있는 value 들을 보면 마치 관계형 데이터베이스의 테이블의 구조와 닮아 있다. 위의 enum을 table model 로 나타내면 아래와 같다.

  breakfastMenu lunchMenu dinnerMenu
MONDAY "빵" "도시락" "샐러드"
TUESDAY "빵" "고구마" "고기"
WEDNESDAY "미역국" "도시락" "샐러드"
THURSDAY "샐러드" "햄버거" "카레"
FRIDAY "카레" "샐러드" "고기"
SATURDAY null "햄버거" "피자"
SUNDAY null "샐러드" "치킨"

enum의 상수:values 구조가 행:열의 2차원 구조로 되어 있고 관계형 데이터베이스의 데이터들 또한 이렇게 구성되어 있기 때문에 서로 닮아 있다.

 

 

활용

데이터베이스의 테이블 중에 runtime 중 절대로 변하지 않는 value를 가진 테이블이 있다면 enum으로 대체할 수 있을 것이다. 데이터베이스를 사용하는 cost 를 절약할 수도 있고 형상관리툴을 사용한다면 상수와 values 의 생성/변경/삭제 등의 이력을 관리하기에도 용이할 것이다.