본문 바로가기

Enum

  자바 1.5 이전에는 상수를 정의할때 `private final static`을 이용해서 상수값을 관리했다. `enum`이 등장한 이유와 `enum`을 사용하면 어떤장점이 있는지 `enum`을 사용하면 얻는 장점을 정리해보자. 

 

 

정수 열거 패턴  vs enum

대부분의 개발자들은 아래와 같이 상태를 정의할때 정수를 열거하는 방식을 사용해본 경험이 한번쯤은 있다. 이를 정수 열거 패턴이라고 하는데 정수 열거패턴은 치명적인 단점이 있다. 판매상태를 보내야하는 메서드의 파라미터로 배송상태를 넘겨줘도 아무 문제 없이 동작하게 된다. 

private final static int SELLING_STOP = 0;
private final static int SELLING_START = 1;
private final static int DELIVERY_STOP = 0;
private final static int DELIVERY_START = 1

 

여기서 `final static`을 붙이는 이유는 상태값을 고정시키기 위해서이다. `final`만 붙이게되면 객체 인스턴스를 생성할때 생성자를 통해 서로 다른 상태값을 부여해서 오류가 발생할 가능성이 있다.  아래와 같은 코드가 있을때 인스턴스 생성시점에서 자유롭게 상태값을 변경할 가능성이 존재한다. 즉, `final`멤버 변수는 반드시 상수가 되는것이 아니라 인스턴스  내부에서는 변하지 않지만 클래스 레벨에서는 언제든 변경될 가능성이 존재한다. 반면, static키워드는 프로그램 실행 직후부터 끝날 때까지 메모리 수명에 올라가 있는다.

 

@Getter
public class DeliveryStatus {
	
    private final int DELVERY_START;
    private final int DELIVERY_STOP;
    
    public DeliveryStatus(int value1,int value2) {
       this.DELIVERY_START = value1;
       this.DELIVERY_STOP = value2;
    }
    
}

 

 

 

 

배송상태를 변경해주는메서드인데 status에 DELIVERY관련 상태가 아니라 판매관련 상태를 넘겨줘도 아무문제 없이 동작한다.

public void changeDeliveryStatus(int staus) {

  if(status == DELIVERY_STOP) {
     //
     //
  }

}

 

 

 

   자바의 enum은 C#과 같은 다른 언어의 열거 타입과 형태는 비슷하지만 자바 enum은 완전한 클래스여서 다른 언어의 enum보다 강력한 기능을 제공해준다. 임의의 메서드나 필드를 추가해서 객체지향적인 코드가 나오게된다. (자신의 상태와 행위는 자신이 컨트롤한다)  

  이펙티브 자바에 나와있는 설명인데 Orange라는 enum이 있으면 Orange의 색을 알려주거나 Orange의 이미지를 반환하는 메서드를 Orange enum에 추가시키면 훨씬 깔끔한 코드가 된다.

 

 

If문 줄이기

  웹애플리케이션을 개발하면 수많은 상태가 존재한다. 등록대기,판매중,판매중지... 이런 상태코드들을 저장할때 DB에는 정수값으로 저장한다. 하지만 정수값을 그대로 애플리케이션 코드단에서 사용하면 가독성이 많이떨어져서 관리하기가 힘들어진다. 또한 상태가 많아지면서 상태별로 다른 로직이 들어가게되면 엄청난 if문이 생긴다.

 

  `enum`을 이용해서 if문을 줄일수 있다. `enum`은 상태를 가지고 있는데 상태별로 다른 행위를 하도록 만들고 싶으면 if문대신 enum에 메서드를 생성해서 if문을 줄일수있다.

 

public enum Operation {

  PLUS {
  	public double apply(double x, double y) {
    	return x + y;
    }
  },
  
  MINUS {
  	public double apply(double x, double y) {
    	return x - y;
    }
  };
  
  public abstract double apply(double x, double y);
}

 

 

상품의 배송타입별로 구매한시간이 언제냐에 따라서 배송날짜가 정해지는 로직을 enum으로 구현했다. `if`문으로만 구현했으면 `if`문 중첩이 많이 생기겠지만 조금 더 객체지향적으로 구현을 했다. (if문을 완전없애는 방법이 있을려나...?) 

 


import java.time.LocalDateTime;

public enum DeliveryType {

  SAMEDAY {
    @Override
    LocalDateTime complete(LocalDateTime payDay) {

      int targetHour = payDay.getHour();

      if(targetHour < 9) return payDay.withHour(18).withMinute(0);
      return payDay.plusDays(1).withHour(18).withMinute(0);

    }
  }

  ,EARLYMORNING {
    @Override
    LocalDateTime complete(LocalDateTime payDay) {
      int targetHour = payDay.getHour();
      if(targetHour < 23) return payDay.plusDays(1).withHour(7).withMinute(0);
      return payDay.plusDays(2).withHour(7).withMinute(0);
    }
  };

  abstract LocalDateTime complete(LocalDateTime payDay);

}

 

import static org.junit.jupiter.api.Assertions.*;

import java.time.LocalDateTime;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class DeliveryTypeTest {

  @Test
  void 오전9시_이전에_주문완료하면_당일배송() {
    LocalDateTime completeDate = DeliveryType.SAMEDAY.complete(LocalDateTime.of(2020,8,22,8,55));
    Assertions.assertEquals(completeDate,LocalDateTime.of(2020,8,22,18,0));
  }

  @Test
  void 오전9시_이후에_주문완료하면_내일배송() {
    LocalDateTime completeDate = DeliveryType.SAMEDAY.complete(LocalDateTime.of(2020,8,22,9,3));
    Assertions.assertEquals(completeDate,LocalDateTime.of(2020,8,23,18,0));
  }

  @Test
  void 오후23시이전에_결제완료된_신선제품은_내일_오전_7시이전에_배송() {
    LocalDateTime completeDate = DeliveryType.EARLYMORNING.complete(LocalDateTime.of(2020,8,22,9,3));
    Assertions.assertEquals(completeDate,LocalDateTime.of(2020,8,23,7,0));
  }

  @Test
  void 오후23시이후에_결제완료된_신선제품은_모레_오전_7시이전에_배송() {
    LocalDateTime completeDate = DeliveryType.EARLYMORNING.complete(LocalDateTime.of(2020,8,22,23,3));
    Assertions.assertEquals(completeDate,LocalDateTime.of(2020,8,24,7,0));
  }

}

 

 

enum으로 모든것을 해결하지 못하지만 enum을 적절하게 잘 활용하면 이펙티브자바에 나온 말처럼 정말 강력한 도구가 될것같다. 객체의 행위와 상태를 자신이 직접 컨트롤함으로써 조금 더 객체지향적인 코드가 나오지 않을까 생각해본다.

 

참고

 

 

Java: enum의 뿌리를 찾아서...

이번 글에서는 자바 1.5버전부터 새롭게 추가된 열거형 상수인 enum(enumeration)에 대해 알아보겠습니다. 열거형은 서로 연관된 상수들의 집합입니다. 이번 글은 enum 정의와 enum 사용방법, 그리고 enum

www.nextree.co.kr

 

 

enum (이전 방식, 개념, 동작방식, 사용예제, 관련메소드)

참조문서 : https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html 1. enum 이란? enumeration의 앞글자로 열거라는 뜻이다. JDK 1.5 부터 관련이 있는 상수들의 집합을 사용할 때 enum을 사용한다. e..

sjh836.tistory.com

 

[Java] Enum 사용법 - 초급(Enum 입문하기)

클린코드 책을 읽다보면 Enum 활용의 중요성에 대해 얘기하는 부분이 있습니다. 이번 글에서는 Enum에 대해 알아보고 Enum을 활용하여 기존의 코드를 개선시켜보도록 하겠습니다. 1. Enum이란? [ Enum �

mangkyu.tistory.com

 

댓글