ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 20221224 TIL enum으로 리팩토링!
    TIL 2022. 12. 24. 22:56

     

    며칠 전 짝꿍님께서 올려주신 TIL에서 enum을 이용해서 리팩토링을 진행했다는 글을 보고,

    나도 enum을 적용할 수 있는 부분이 있는 것 같아서 적용을 해보았다!

    그렇지 않아도 작은 오타로 문제가 발생할 수 있을 것 같아서 리팩토링을 하는 게 좋지 않을까 생각해보고 있었는데,

    짝꿍님의 도전으로 나도 용기를 내어 리팩토링을 시도해보았다.

     

    enum은 인스턴스의 개수가 정해져있는 경우에 사용하게 된다.

    대표적으로 상태 값을 사용할 때 유용한 것 같다.

    내가 만든 VO 중에 질문 상태에 대한 VO가 있었고, 이 부분을 enum을 이용해서 리팩토링해보았다.

    기존에는 아래와 같은 상태였다.

    값 객체이기에 equals와 hashCode를 오버라이딩 해주었다.

    // models/QuestionStatus.java
    
    @Embeddable
    public class QuestionStatus {
        private static final QuestionStatus OPEN =
                new QuestionStatus("open");
        private static final QuestionStatus CLOSED =
                new QuestionStatus("closed");
    
        @Column(name = "questionStatus")
        private String value;
    
        public QuestionStatus() {
        }
    
        public QuestionStatus(String value) {
            this.value = value;
        }
    
        public static QuestionStatus open() {
            return OPEN;
        }
    
        public static QuestionStatus closed() {
            return CLOSED;
        }
    
        public String value() {
            return value;
        }
    
        @Override
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }
    
            if (other == null || getClass() != other.getClass()) {
                return false;
            }
    
            QuestionStatus otherQuestionStatus = (QuestionStatus) other;
    
            return Objects.equals(value, otherQuestionStatus.value);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(value);
        }
    }

     

    enum을 사용하면, equals와 hashCode를 재정의해주지 않아도 되고, 아래와 같이 리팩토링 할 수 있다.

    코드가 훨씬 간결해졌고, 실수가 발생할 확률이 낮아졌다.

    // models/QuestionStatus.java
    
    public enum QuestionStatus {
        OPEN("open"),
        CLOSED("closed");
    
        private static final Map<String, String> STATUS_MAP = Collections.unmodifiableMap(
                Stream.of(values()).collect(Collectors.toMap(QuestionStatus::value, QuestionStatus::name))
        );
    
        private String value;
    
        QuestionStatus() {
        }
    
        QuestionStatus(String value) {
            this.value = value;
        }
    
        public String value() {
            return value;
        }
    
        public static QuestionStatus of(final String value) {
            return QuestionStatus.valueOf(STATUS_MAP.get(value));
        }
    }

    질문의 상태에 따라서 필터링을 해야했기 때문에 위와 같이

    "open", "closed" 등의 status를 받아서 enum 타입으로 반환하는 정적 팩토리 메서드도 만들어 보았다.

     

    아래와 같은 테스트 코드를 통해 잘 작동하는지 검증해볼 수 있다.

    class QuestionStatusTest {
        @Test
        void of() {
            String status = "open";
    
            QuestionStatus questionStatus = QuestionStatus.of(status);
    
            assertThat(questionStatus.value()).isEqualTo(status);
        }
    }

     

    그리고 enum타입을 사용하고 있는 @Entity에서 아래와 같이 @Enumerated(EnumType.STRING)을 붙여주면 

    DB에 enum의 name (내 코드에서는 OPEN 과 CLOSED)이 숫자형 대신 저장된다.

    // models/Question.java
    
    @Enumerated(EnumType.STRING)
    private QuestionStatus status;

     

    한 가지 걱정되는 부분은 Specification을 정의해둔 부분이었는데,

    enum타입을 사용하는 경우에도 criteriaBuilder.equal이 잘 적용이 된다!

     

    프로젝트를 하면서 다채로운 방법들을 익히고 있다!

    에러를 해결하지 못하는 동안은 끝이 없는 터널을 걷는 기분이지만, 해결을 하고 나면 생각보다 별 것이 아닌 것 같다.

    더 좋은 방식이 있다면 과감하게 시도를 해보자.

     

    참고

    https://sunghs.tistory.com/126

    댓글

Designed by Tistory.