자바 Enum에 대해 알아보자.

김준석·2023년 2월 13일
0

공부하게 된 계기

졸업프로젝트를 하면서, 클래스 내에 필드에
(봄, 여름, 가을, 겨울)
(시트러스향, 우디향, 플로럴향)
같은 열거가 필요한 상수를 많이 사용하였다. 점점 코드의 양이 많아지니까, 정의할 것이 계속 생겨나고, 가독성을 해치는 것 같다고 느껴져서 확실하게 알고 있지 못했던 Enum 클래스에 대한 공부를 했다.


Enum이란?

  • 위에 계기에서 언급한 열거 상수를 표현할 수 있는 서로 연관된 상수들의 집합이다.
  • 열거 상수들 각각 내부적으로 static final한 필드이면서 객체로 제공해준다. 따라서 메모리 할당 또한 프로그램 종료 시에 해제된다.
  • 열거 객체들은 java.lang.Enum 클래스를 상속받기 때문에 values(), valueOf(String name), compareTo(), name(), ordinal() 메서드를 사용할 수 있다.

장점은?

  • 문자열과 비교해, IDE의 적극적인 지원을 받는다. (자동완성, 오타검증, 텍스트 리팩토링 등)
  • 허용 가능한 값들을 제한할 수 있다.
  • 내용의 추가를 하더라도, Enum외의 코드를 수정할 필요가 없다.
  • 코드가 단순해지며, 가독성이 좋아진다.
  • Enum 자체가 열거형이라는 구현의 의도임을 명확하게 밝힐 수 있다.
  • 등 여러가지가 있다!

나는 무슨 이유로 Enum을 사용했을까?

밑 코드는 향(시트러스,우디 등)에 따른 메세지를 return해주는 메소드이다.

    public String selectScent(Long id) {
        Survey survey = findFeature(id);
        String message = "";
        if (survey.getScentAnswer().equals(CITRUS)) {
            message = ScentMessage.CITRUS_MESSAGE;
        }
        if (survey.getScentAnswer().equals(SOAPY)) {
            message = ScentMessage.SOAPY_MESSAGE;
        }
        if (survey.getScentAnswer().equals(WOODY)) {
            message = ScentMessage.WOODY_MESSAGE;
        }
        if (survey.getScentAnswer().equals(FLORAL)) {
            message = ScentMessage.FLORAL_MESSAGE;
        }
        if (survey.getScentAnswer().equals(FRUITY)) {
            message = ScentMessage.FRUITY_MESSAGE;
        }
        if (survey.getScentAnswer().equals(VANILLA)) {
            message = ScentMessage.VANILLA_MESSAGE;
        }
        return message;

해당 코드의 문제점은

  • 향이 늘어나면, IF문 분기를 더 작성해야 한다. 그에따른 ScentMessage도 추가해줘야 한다. 즉 확장성이 무척 낮다.
  • 그로 인해 당연히 가독성도 Down..
  • 가독성이 낮아졌으니.. 실수로 누락하거나, 다른 값을 사용할 가능성이 높아진다.
  • 즉! 유지보수가 어려워진다 ㅜ.

그래서 Enum을 사용했다.


  • Enum 객체 ScentType 생성
public enum ScentType {

    CITRUS("시트러스", "당신은 오렌지나 자몽처럼 상큼한 향을 좋아하시는군요! 신선한 향은 당신을 더욱 매력적으로 보이게 할 거예요 :)"),
    WOODY("우디", "당신은 자연에서 나는 듯한 냄새와 잘 어울릴 것 같아요! 우디향 향수는 당신을 더욱 매력적인 사람으로 만들거예요 :)"),
    SOAPY("소피", "당신은 은은하게 나는 비누향과 잘 어울릴 것 같아요! 깔끔하고 단정한 이미지를 만들어보아요 :)"),
    FRUITY("프루티", "당신은 달콤한 과일같은 향기와 잘 어울릴 것 같아요! 이런 향수를 쓰면 지나간 사람들이 한번씩 뒤돌아볼 것 같아요 :)"),
    FLORAL("플로럴", "당신은 우아하고 고급스러운 꽃 향과 잘 어울릴 것 같아요! 꽃 향기로 당신의 매력을 어필해보세요 :)"),
    VANILLA("바닐라", "당신은 달짝지근한 향수와 잘 어울릴 것 같아요! 은은하게 퍼지는 향은 당신을 더욱 매력적인 사람으로 만들거예요 :)");

    private String scent;
    private String feature;

    ScentType(String scent, String feature) {
        this.scent = scent;
        this.feature = feature;
    }

    public static String getFeature(Survey survey) {
        String expectedScent = survey.getScentAnswer();
        ScentType scentType = Arrays.stream(ScentType.values())
                .filter(scent -> scent.getScent().equals(expectedScent))
                .findAny().orElseThrow(SurveyNotFoundException::new);
        return scentType.getFeature();
    }
}
  • Enum 객체 사용
    public String selectScent(Long id) {
        Survey survey = findFeature(id);
        return ScentType.getFeature(survey);
    }
  • 상수 Message(Scent.CITRUS_MESSAGE)를 담았던 객체 또한 Enum객체에 한꺼번에 담았다.
  • Stream으로 Enum의 상수들을 순회하면서 찾아서 selectScent의 난잡했던 분기문이 사라졌다!
  • 결과적으로 코드가 깔끔해졌고, 향이 추가된다면 Enum객체 내에 해당 향만 추가해주면 된다.

기존 코드와의 비교


  • 수정 전
public class ScentMessage {


    private static final String CITRUS = "시트러스";
    private static final String WOODY = "우디";
    private static final String SOAPY = "소피";
    private static final String FLORAL = "플로럴";
    private static final String FRUITY = "프루티";
    private static final String VANILLA = "바닐라";
    
    public static final String CITRUS_MESSAGE =
            "당신은 오렌지나 자몽처럼 상큼한 향을 좋아하시는군요! 신선한 향은 당신을 더욱 매력적으로 보이게 할 거예요 :)";
    public static final String FLORAL_MESSAGE =
            "당신은 우아하고 고급스러운 꽃 향과 잘 어울릴 것 같아요! 꽃 향기로 당신의 매력을 어필해보세요 :)";
    public static final String WOODY_MESSAGE =
            "당신은 자연에서 나는 듯한 냄새와 잘 어울릴 것 같아요! 우디향 향수는 당신을 더욱 매력적인 사람으로 만들거예요 :)";
    public static final String SOAPY_MESSAGE =
            "당신은 은은하게 나는 비누향과 잘 어울릴 것 같아요! 깔끔하고 단정한 이미지를 만들어보아요 :)";
    public static final String FRUITY_MESSAGE =
            "당신은 달콤한 과일같은 향기와 잘 어울릴 것 같아요! 이런 향수를 쓰면 지나간 사람들이 한번씩 뒤돌아볼 것 같아요 :)";
    public static final String VANILLA_MESSAGE =
            "당신은 달짝지근한 향수와 잘 어울릴 것 같아요! 은은하게 퍼지는 향은 당신을 더욱 매력적인 사람으로 만들거예요 :)";

}

public class FeatureService {
    
    public String selectScent(Long id) {
        Survey survey = findFeature(id);
        String message = "";
        if (survey.getScentAnswer().equals(CITRUS)) {
            message = ScentMessage.CITRUS_MESSAGE;
        }
        if (survey.getScentAnswer().equals(SOAPY)) {
            message = ScentMessage.SOAPY_MESSAGE;
        }
        if (survey.getScentAnswer().equals(WOODY)) {
            message = ScentMessage.WOODY_MESSAGE;
        }
        if (survey.getScentAnswer().equals(FLORAL)) {
            message = ScentMessage.FLORAL_MESSAGE;
        }
        if (survey.getScentAnswer().equals(FRUITY)) {
            message = ScentMessage.FRUITY_MESSAGE;
        }
        if (survey.getScentAnswer().equals(VANILLA)) {
            message = ScentMessage.VANILLA_MESSAGE;
        }
        return message;
    }
}
        
  • 바뀐 코드 (그 외의 코드들은 지웠습니다.)
public enum ScentType {

    CITRUS("시트러스", "당신은 오렌지나 자몽처럼 상큼한 향을 좋아하시는군요! 신선한 향은 당신을 더욱 매력적으로 보이게 할 거예요 :)"),
    WOODY("우디", "당신은 자연에서 나는 듯한 냄새와 잘 어울릴 것 같아요! 우디향 향수는 당신을 더욱 매력적인 사람으로 만들거예요 :)"),
    SOAPY("소피", "당신은 은은하게 나는 비누향과 잘 어울릴 것 같아요! 깔끔하고 단정한 이미지를 만들어보아요 :)"),
    FRUITY("프루티", "당신은 달콤한 과일같은 향기와 잘 어울릴 것 같아요! 이런 향수를 쓰면 지나간 사람들이 한번씩 뒤돌아볼 것 같아요 :)"),
    FLORAL("플로럴", "당신은 우아하고 고급스러운 꽃 향과 잘 어울릴 것 같아요! 꽃 향기로 당신의 매력을 어필해보세요 :)"),
    VANILLA("바닐라", "당신은 달짝지근한 향수와 잘 어울릴 것 같아요! 은은하게 퍼지는 향은 당신을 더욱 매력적인 사람으로 만들거예요 :)");

    private String scent;
    private String feature;

    ScentType(String scent, String feature) {
        this.scent = scent;
        this.feature = feature;
    }

    public static String getFeature(Survey survey) {
        String expectedScent = survey.getScentAnswer();
        ScentType scentType = Arrays.stream(ScentType.values())
                .filter(scent -> scent.getScent().equals(expectedScent))
                .findAny().orElseThrow(SurveyNotFoundException::new);
        return scentType.getFeature();
    }
}

public class FeatureService {

    public String selectScent(Long id) {
        Survey survey = findFeature(id);
        return ScentType.getFeature(survey);
    }
}

도움 많이많이 받은 참고자료
우아한 형제들 기술블로그

profile
기록하면서 성장하기!

0개의 댓글