일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 안드로이드
- join
- 자바
- 안드로이드스튜디오
- 스터디
- CS
- 코테
- 정처기
- Kotlin
- 알고리즘
- 티스토리챌린지
- 혼공단
- 프로그래머스
- 정보처리기사
- 카카오코테
- SQL
- groupby
- doitandroid
- java
- 자료구조
- Til
- 오블완
- 혼공파
- select
- 인프런
- Android
- 혼공챌린지
- MySQL
- 코틀린
- 기술면접
- Today
- Total
Welcome! Everything is fine.
[Java/Spring] 인터페이스 vs enum 클래스 vs final 클래스 - 상수 관리하는 법 본문
지난 프로젝트에서 다른 팀원 분이 상수를 인터페이스로 관리하는 것을 봤다. final 클래스나 enum 클래스를 사용하는 것이 더 나은 것이 아닐까? 하는 궁금증이 들어 검색도 해보고 튜터님께 찾아가 질문해봤다.
예시 코드는 내가 작성한 에러 메세지 enum 클래스인데, GPT한테 각각의 경우에 맞게 수정을 해달라고 해봤다.
final 클래스로 상수 관리하기
상수를 관리하려고 할 때 사용되는 가장 고전적인 방법이 아닐까 싶다. final 클래스를 만들고 , 상수들을 static final로 선언한다. 이렇게 하면 정적 import를 통해 클래스 이름을 생략해서 사용할 수 있다는 장점이 있다. 하지만 확장성과 유지보수성 측면에서 enum보다 떨어진다. 만약 final 클래스로 상수를 관리한다면 기본 생성자를 private으로 설정해 인스턴스화를 방지하는 것을 잊지 말자.
public final class ErrorOrderMessages {
public static final String CANNOT_CANCEL_ORDER = "취소할 수 없는 주문입니다.";
public static final String ONLY_USER_CAN_CANCEL = "본인의 주문만 취소할 수 있습니다.";
public static final String ORDER_NOT_FOUND = "주문 내역이 존재하지 않습니다.";
public static final String MINIMUM_ORDER_NOT_MET = "최소 주문 금액 이상 주문해야 합니다.";
public static final String NOT_BUSINESS_HOURS = "현재 영업 시간이 아닙니다.";
public static final String NOT_OWNER_ORDER = "본인 가게 주문만 처리할 수 있습니다.";
public static final String ALREADY_DELIVERING_OR_COMPLETED = "이미 배달이 시작되었거나 완료된 주문입니다.";
public static final String MUST_BE_ACCEPTED_BEFORE_COOKING = "주문 접수 후에 조리를 시작할 수 있습니다.";
public static final String MUST_BE_COOKING_BEFORE_DELIVERY = "조리를 시작한 주문만 배달할 수 있습니다.";
public static final String MUST_BE_DELIVERING_BEFORE_COMPLETE = "배달중인 주문만 배달 완료 처리를 할 수 있습니다.";
public static final String ALREADY_COMPLETED = "이미 배달이 완료된 주문입니다.";
private ErrorOrderMessages() {} // 인스턴스화 방지
}
튜터님은 상속 방지가 더 중요하다거나 캡슐화 자체가 중요하다면 final 클래스를 추천할 수도 있다고 하셨다.
interface로 상수 관리하기
인터페이스의 역할이 뭘까? 인터페이스는 어떤 클래스를 구현할 때 틀을 제공해주는 역할을 한다. 하지만 아래와 같은 경우는 틀을 제공하는 것이 아니라 이미 정해놓은 상수를 모아두는 역할을 할 뿐이다. 이렇게 인터페이스의 역할을 벗어나면 이를 구현하는 클래스들 사이의 일관성이 떨어지게 된다.
public interface ErrorOrderMessage {
String CANNOT_CANCEL_ORDER = "취소할 수 없는 주문입니다.";
String ONLY_USER_CAN_CANCEL = "본인의 주문만 취소할 수 있습니다.";
String ORDER_NOT_FOUND = "주문 내역이 존재하지 않습니다.";
String MINIMUM_ORDER_NOT_MET = "최소 주문 금액 이상 주문해야 합니다.";
String NOT_BUSINESS_HOURS = "현재 영업 시간이 아닙니다.";
String NOT_OWNER_ORDER = "본인 가게 주문만 처리할 수 있습니다.";
String ALREADY_DELIVERING_OR_COMPLETED = "이미 배달이 시작되었거나 완료된 주문입니다.";
String MUST_BE_ACCEPTED_BEFORE_COOKING = "주문 접수 후에 조리를 시작할 수 있습니다.";
String MUST_BE_COOKING_BEFORE_DELIVERY = "조리를 시작한 주문만 배달할 수 있습니다.";
String MUST_BE_DELIVERING_BEFORE_COMPLETE = "배달중인 주문만 배달 완료 처리를 할 수 있습니다.";
String ALREADY_COMPLETED = "이미 배달이 완료된 주문입니다.";
}
하지만 튜터님 중 한 분은 인터페이스를 선호하진 않지만, 상수만을 저장하는 용도라고 한다면 인터페이스도 많이 사용할 것 같다고 말씀해주셨다. 혹은 상수 재사용이 제일 중요하다 하면 인터페이스를 주로 쓸 수 있을 것이라고 하셨다.
enum 클래스로 상수 관리하기
만약 에러 메세지를 여러 언어로 제공해야 하는 경우가 생긴다면 어떨까? enum 클래스를 사용한다면 그냥 필드 하나만 추가해주면 돼서 유지보수가 더 쉽다. enum은 특히 잘못된 값을 방지할 수 있어 타입 안정성을 보장한다는 장점이 있다.
@Getter
public enum ErrorOrderMessage {
CANNOT_CANCEL_ORDER("취소할 수 없는 주문입니다."),
ONLY_USER_CAN_CANCEL("본인의 주문만 취소할 수 있습니다."),
ORDER_NOT_FOUND("주문 내역이 존재하지 않습니다."),
MINIMUM_ORDER_NOT_MET("최소 주문 금액 이상 주문해야 합니다."),
NOT_BUSINESS_HOURS("현재 영업 시간이 아닙니다."),
NOT_OWNER_ORDER("본인 가게 주문만 처리할 수 있습니다."),
ALREADY_DELIVERING_OR_COMPLETED("이미 배달이 시작되었거나 완료된 주문입니다."),
MUST_BE_ACCEPTED_BEFORE_COOKING("주문 접수 후에 조리를 시작할 수 있습니다."),
MUST_BE_COOKING_BEFORE_DELIVERY("조리를 시작한 주문만 배달할 수 있습니다."),
MUST_BE_DELIVERING_BEFORE_COMPLETE("배달중인 주문만 배달 완료 처리를 할 수 있습니다."),
ALREADY_COMPLETED("이미 배달이 완료된 주문입니다.");
private final String message;
ErrorOrderMessage(String message) {
this.message = message;
}
}
- 타입 안정성 향상 : 사전에 정의된 상수들로만 구성되므로 유효한 값만 입력된다. 유효하지 않은 값이 들어오면 컴파일 오류가 발생한다.
- 간결성 및 일관성 : 코드가 더 간결해지고 명확해지며, 데이터 일관성이 보장된다.
- 확장성 : enum에 새로운 상수를 추가하기만 하면 간편하게 확장이 가능하다.
결론
검색해서도 혹은 튜터님께 질문을 해서도 조금씩 의견이 다른 부분이 있었지만, 대부분 타입 안정성과 확장성 측면에서 enum을 주로 선호하는 것 같았다.
결론 : 그냥 enum 쓰자.
'TIL' 카테고리의 다른 글
QueryDSL 사용하기(with JPA) (0) | 2025.03.22 |
---|---|
[AWS] 🪣S3 시작하기 - bucket 만들기, bucket policy 설정, 정적 웹 사이트 호스팅, EC2에 S3 권한 주기 (0) | 2025.03.21 |
[AWS] RDS 가볍게 시작해보기! (0) | 2025.03.18 |
[Spring] Spring Security 도입 후 NullPointException 해결(@AuthenticationPrincipal) (3) | 2025.03.14 |
[Spring] application.yml에 시크릿 키 넣지 말아주세요...(.env 파일 만들고 설정하기) (0) | 2025.03.10 |