[Java] Enum 클래스

프로그래밍에서 enum은 여러 항목을 나열한 집합, 즉 미리 정의된 상수들의 묶음을 말한다. 이 글에서는 enum의 개념과 필요성 그리고 enum을 활용한 객체 지향적인 코드의 장점을 살펴보고자 한다.

 

문자열과 타입 안전성

자바에서 Enum Type은 왜 제공할까? 아래 예제를 통해 확인해 보자.

회원등급은 'BASIC', 'GOLD', 'DIAMOND' 총 3등급이 있다. 개발자는 회원 등급에 다른 할인율을 제공하기 위해 아래와 같은 코드를 작성했다.

public class DiscountService {
	public int discount(String grade, int price) {
    int discountPercent = 0;
    
    if (grade.equals("BASIC")) {
    	discountPercent = 10;
    } else if (grade.equals("GOLD")) {
    	discountPercent = 20;
    } else if (grade.equals("DIAMOND")) {
    	discountPercent = 30;
    } else {
    	System.out.println(grade + ":할인x");
    }
    	return price * discountPercent / 100;
    }
 }

 

이 코드의 문제점은 무엇일까? 코드를 보면 등급이 문자열로 입력되는 것을 알 수 있다. 이는 오타가 발생하기 쉽고 유효하지 않는 값이 입력되는 문제를 초래할 수 있다. 이를 '타입 안정성이 부족하다'라고 한다. String 타입을 사용할 시 값의 제한을 할 수 없다. 'DIAMND'와 같이 잘못된 값이 입력되어도 컴파일 시 오류가 감지되지 않고 런타임에서만 문제를 발견할 수 있다.

 

그렇다면 문자열 상수를 사용해 보는 것은 어떨까? 상수는 미리 정의한 변수명을 사용할 수 있기 때문에 문자열 사용보다 안전하다.

public class StringGrade {
    public static final String BASIC = "BASIC";
    public static final String GOLD = "GOLD";
    public static final String DIAMOND = "DIAMOND";
}

문자열 상수 사용 시 실수로 이름을 잘못 입력하면 컴파일 시점에 오류가 발생한다. 그러나 문자열 상수 또한 근본적인 해결 방법이 아니다. 위의 discount() 메서드를 보면 받을 수 있는 인자가 String으로 되어 있기 때문에 정의된 문자열 상수를 사용하지 않고 문자열을 직접 입력할 수 있다. discount()를 호출하는 개발자는 문자열 상수의 존재를 모를 수 있다.

 

타입 안전 열거형 패턴 

이러한 문제들을 해결하기 위해 타입 안전 열거형 패턴 (Type-Safe Enum Pattern)을 도입한다. 나열한 항목이 아닌 것은 사용할 수 없도록 설계하여 위와 같은 문제가 생길 가능성을 원천 차단하는 것이다.

 

타입 안전 열거형 패턴을 직접 구현해 보자.

public class ClassGrade {
    public static final ClassGrade BASIC = new ClassGrade();
    public static final ClassGrade GOLD = new ClassGrade();
    public static final ClassGrade DIAMOND = new ClassGrade();
    
    //private 생성자 추가
    private ClassGrade() {}
}

1. 회원 등급을 다루는 클래스를 만들고 회원 등급별로 상수를 선언한다.
2. 이때 각각의 상수마다 별도의 인스턴스를 생성하고 생성한 인스턴스를 대입한다.
3. 상수로 선언하기 위해 static, final을 사용한다. (static: 상수를 메서드 영역에 선언/ final: 인스턴스(참조값) 변경할 수 없게 함)
4. private 생성자를 사용해 외부에서 ClassGrade를 임의로 생성하지 못하도록 한다.

 

이렇게 타입 안전 열거형 패턴을 사용하게 되면 정해진 객체만을 사용할 수 있어 타입 안정성이 향상되고 데이터 일관성을 보장할 수 있다.

 

자바의 Enum 클래스

자바는 타입 안전 열거형 패턴을 쉽게 사용할 수 있게 열거형(Enum Type)을 제공한다. 

public enum Grade {
	BASIC, GOLD, DIAMOND
}

이 코드는 위의 타입 안전 열거형 패턴 코드와 같은 역할을 한다. 자바의 Enum은 하나의 클래스이며 java.lang.Enum을 상속받아 동작한다. 열거형 사용으로 코드의 간결성과 일관성을 보장할 수 있다. 또한 확장성과 유연성도 뛰어나다. 새로운 회원 등급을 추가하고 싶다면 enum에 새로운 상수를 추가하기만 하면 된다.

예를 들어, Enum을 통해 회원 등급을 정의하면 특정 등급에 대한 로직을 Enum 내부에 직접 포함시킬 수 있어 코드의 응집도를 높일 수 있다. 아래의 코드처럼 enum 클래스를 활용해 객체 지향 코드로 리팩터링 할 수 있다.

public enum Grade {
    BASIC(10), GOLD(20), DIAMOND(30);
    
    private final int discountPercent;
    
    Grade(int discountPercent) {
        this.discountPercent = discountPercent;
    }
    public int getDiscountPercent() {
        return discountPercent;
    }
    
    public int discount(int price) {
        return price * discountPercent / 100;
    }
    
}

 

정리

자바의 Enum 타입은 타입 안정성을 보장한다. 문자열이나 상수를 사용하는 것보다 안전하고 효율적이며 코드의 확장성과 유지보수성을 향상할 수 있다. 따라서 여러 상수값을 관리하고 로직을 구현할 때 Enum을 활용하는 것이 좋다.

참고

김영한의 실전 자바 - 중급 1