과정을 즐기자

enum class로 상수를 관리해야하는 이유 본문

Java

enum class로 상수를 관리해야하는 이유

320Hwany 2023. 6. 22. 13:25

개발을 하다보면 상수를 관리해야할 경우가 있습니다.

상수를 사용하는 곳마다 하드코딩을 하지 않고 따로 클래스를 만들면 효율적으로 관리할 수 있습니다.

그래서 Error 메세지를 관리하는 클래스인 ErrorMessageConstant를 만들어서 사용하고 있었습니다.

하지만 이 방식은 완벽한 싱글톤을 보장하지 못한다는 문제점이 있습니다. 

 

Before

먼저 기존에 상수를 관리하던 방식부터 살펴보겠습니다.  

ErrorMessageConstant

public class ErrorMessageConstant {

    private ErrorMessageConstant() {
    }

    public static final String MEMBER_DUPLICATION_MESSAGE = "이미 가입된 회원입니다";

    public static final String MEMBER_AUTHENTICATION_MESSAGE = "로그인 후 이용해주세요";
}

private 생성자로 외부에서 인스턴스화 할 수 없게 만들고 필드 상수 값들은 외부에서 사용할 수 있도록 했습니다.  

이렇게 만들었기 때문에 ErrorMessageConstant는 싱글톤을 보장할 수 있다고 생각할 수 있습니다.  

하지만 Reflection을 이용한다면 인스턴스화를 할 수 있습니다.   

 

ErrorMessageConstantTest

class ErrorMessageConstantTest {

    @Test
    @DisplayName("private 생성자로 인스턴스화를 막았더라도 Reflection을 "
   		 		+ "이용하면 인스턴스화 할 수 있습니다")
    void makeInstance() throws Exception {
        // ErrorMessageConstant 클래스 가져오기
        Class<?> errorMessageConstantClass =
                Class.forName("com.example.javatest.enum_type.ErrorMessageConstant");

        // private 생성자 가져오기
        Constructor<?> constructor = errorMessageConstantClass.getDeclaredConstructor();

        // private 생성자 접근 가능하도록 설정
        constructor.setAccessible(true);

        // 인스턴스 생성
        Object instance = constructor.newInstance();

        // expected
        assertThat(instance).isInstanceOf(ErrorMessageConstant.class);
    }
}

따라서 private 생성자가 완벽하게 인스턴스화를 막을 수는 없습니다.    

After

이제 enum 클래스를 이용해서 상수를 관리하는 방법으로 리팩토링 해보겠습니다.

ErrorMessageConstant

public enum ErrorMessageConstant {

    MEMBER_DUPLICATE_MESSAGE("이미 가입된 회원입니다"),
    MEMBER_AUTHENTICATION_MESSAGE("로그인 후 이용해주세요");

    public final String message;

    ErrorMessageConstant(String message) {
        this.message = message;
    }
}

Enum 클래스는 외부에서 인스턴스화 할 수 있는 생성자가 없습니다.

위 코드의 생성자는 내부에서 관리되는 상수를 생성하기 위해 존재하는 것입니다.  

마찬가지로 Reflection을 이용해서 인스턴스화 하려고 하면 어떻게 될까요?

ErrorMessageConstantTest

class ErrorMessageConstantTest {

    @Test
    @DisplayName("Enum 클래스의 생성자를 가져오려고 하면 예외가 발생합니다")
    void makeInstance() throws Exception {
    
        // ErrorMessageConstant 클래스 가져오기
        Class<?> errorMessageConstantClass =
                Class.forName("com.example.javatest.enum_type.ErrorMessageConstant");

        // expected
        assertThatThrownBy(errorMessageConstantClass::getDeclaredConstructor)
                .isInstanceOf(NoSuchMethodException.class);
    }
}

생성자를 가져오기 위해 getDeclaredConstructor를 실행하면 기본 생성자를 찾을 수 없어 

NoSuchMethodException이 발생합니다. 

 

정리

클래스의 private 생성자로 인스턴스화를 막더라도 Reflection을 이용하면 인스턴스화가 가능하기 때문에

완벽한 싱글톤을 보장하기 위해서는 enum 클래스를 이용해야 합니다.  

참고한 자료 

 

[Java & Kotlin] enum class가 완벽한 싱글톤이라 불리는 이유

싱글톤 패턴(Singleton Pattern)이란? 싱글톤은 애플리케이션 상 특정 클래스가 최초 한 번만 메모리를 할당하고 그 메모리에 인스턴스를 만들어 사용하는 디자인 패턴을 의미한다. 객체 생성 요청이

dataportal.kr

이펙티브 자바 - 아이템 3 

'Java' 카테고리의 다른 글

자바 쓰레드 관리의 시작  (2) 2023.08.18
자바가 Call By Reference가 아닌 이유  (0) 2023.08.05
Equals와 HashCode 비교  (0) 2022.12.13
추상 클래스와 인터페이스  (0) 2022.11.10
Call by Value, Call by Reference  (0) 2022.10.25