일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 백엔드
- iterator
- text
- foreach
- 동시성
- 동시성 문제
- Synchronized
- 가비지 컬렉션
- 데이터 타입
- 스프링
- java
- reflection
- 가비지 컬렉터
- gc
- Locking Read
- Varchar
- Di
- MySQL
- iterable
- db
- 자바
- Lock
- MVCC
- jpa
- CAS
- Atomic Type
- Today
- Total
과정을 즐기자
enum class로 상수를 관리해야하는 이유 본문
개발을 하다보면 상수를 관리해야할 경우가 있습니다.
상수를 사용하는 곳마다 하드코딩을 하지 않고 따로 클래스를 만들면 효율적으로 관리할 수 있습니다.
그래서 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 클래스를 이용해야 합니다.
참고한 자료
이펙티브 자바 - 아이템 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 |