Item 30. int 상수 대신 enum을 사용하라

고정 개수의 상수들로 값이 구성되는 자료형

int enum 패턴 :사용하면안된다

public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN =1;
...
int i = (APPLE_FUJI - ORANGE_TEMPLE) / APPLE_PIPPIN; // 변수가 섞임
  • int enum 그룹의 크기를 알기 어렵다

  • 디버깅이 불편하다

enum의 특징!

public enum Apple { FUJI, PIPPIN, GRANNY_SMITH}
public enum Orange { NAVEL, TEMPLE, BLOOD }
  • C/C++/C# 언어가 제공하는 enum 이랑 다르게, JAVA에서는 참조 자료형 (다른 언어는 int)

  • 열거 상수 별로 public static final 필드 형태로 제공

  • 클라이언트에서 접근할 수 있는 생성자는 없음. 새로운 객체 생성이나 계승 불가능

  • 컴파일 시점에 형 안전성 제공. (Item 21 참고)

  • 이름 공간 분리되어 있기 때문에 같은 이름의 상수가 공존 가능

  • toString 메서드를 호출 가능해서 문자열로 쉽게 변경 가능

  • Object 에 정의된 메서드들이 포함 되어 있음

  • Comparable, Serializable 인터페이스 구현되어 있음

enum 자료형에 메서드나 필드 추가

public enum Planet {
  MERCURY (3.302e+23, 2.439e6),
  VENUS (3.302e+23, 2.439e6),
  EARTH (5.975e+24, 6.367e6),
  MARS (3.302e+23, 2.439e6),
  JUPITER (3.302e+23, 2.439e6),
  SATURE (3.302e+23, 2.439e6),
  URANUS (3.302e+23, 2.439e6),
  NEPTUNE (3.302e+23, 2.439e6);
​
  private final double mass; // 킬로그램 단위
  private final double radius; // 미터 단위
  private final double surfaceGravity;
  private static final double G = 6.67300E-11; //중력상수
​
  //생성자
  Planet(double mass, double radius){
    this.mass = mass;
    this.radius = radius;
    surfaceGravity = G * mass / (radius * radius);
  }
​
  // 접근자
  public double mass() { return mass; }
  public double radius() { return radius; }
  public double surfaceGravity() { return surfaceGravity; }
​
  // 추가 메서드
  public double surcfaceWight(double mass){
    return mass * surfaceGravity; // F = ma
  }
​
  // 사용
  public static void main(String[] args) {
    double earthWeight = 3.3333;
    double mass = earthWeight / Planet.EARTH.surfaceGravity();
  ​
    // values 라는 static 함수 존재. 이외에도 기본 제공함수들이 많음!
    for(Planet p : Planet.values() ){
      System.out.println(p + " surcfaceWight >>>" +  p.surcfaceWight(mass));
    }
  }
}
  • enum 상수 묶음에서 출발해서 점차로 완전한 기능을 갖춘 추상화 단위로 발전 가능

  • enum 상수에 데이터를 넣으려면 객체 필드를 선언하고, 생성자를 통해 받은 데이터를 그 필드에 저장

  • enum 도 클라이언트에게 공개할 이유가 없다면 private 나 package-private로 선언

  • 공개한다면 최상위 public 클래스로 생성하거나, 최상위 클래스의 멤버 클래스로 선언

  • enum 상수를 선언된 순서대로 저장하는 배열을 반환하는 static values 메소드 기본으로 정의되어 있음

상수별 메서드 구현 (constant-specific method implementation)

public enum Operation {
  //상수별 메서드 구현
  PLUS {double apply(double x, double y){ return x + y;}},
  MINUS{double apply(double x, double y){ return x - y;}},
  TIMES {double apply(double x, double y){ return x * y;}},
  DIVIDE {double apply(double x, double y){ return x / y;}};
​
  abstract double apply(double x, double y);
​
  // 사용
  public static void main(String[] args) {
    double x = 6;
    double y = 3;
    for (Operation op : Operation.values())
      System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
  }
}
  • enum 상수별 각 다른 동작이 필요할 때는, switch 문 대신 상수별 메서드를 구현해야 한다!

  • abstract 메서드가 모든 상수에 반드시 구현해야 하기 때문에 구현 잊을 가능성이 거의 없다

  • 단, 단점은 enum 상수끼리 공유하는 코드를 만들기는 어렵다

코드를 공유하면서 분기가 필요할 경우

enum PayrollDay {
  MONDAY(PayType.WEEKDAY),
  TUESDAY(PayType.WEEKDAY),
  WEDNESDAY(PayType.WEEKDAY),
  THURSDAY(PayType.WEEKDAY),
  FRIDAY(PayType.WEEKDAY),
  SATURDAY(PayType.WEEKEND),
  SUNDAY(PayType.WEEKEND);
​
  private final PayType payType;
​
  PayrollDay(PayType payType) {
    this.payType = payType;
  }
​
  double pay(double hoursWorked, double payRate) {
    return payType.pay(hoursWorked, payRate);
  }
​
  //정책 enum 자료형
  private enum PayType {
    WEEKDAY {
     double overtimePay(double hours, double payRate) {
       return hours <= HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT) * payRate / 2;
     }
    },
    WEEKEND {
      double overtimePay(double hours, double payRate) {
        return hours * payRate / 2;
      }
    };
  ​
    private static final int HOURS_PER_SHIFT = 8;
  ​
    // 추상 메소드! 확장성에 좋다!
    abstract double overtimePay(double hrs, double payRate);
  ​
    double pay(double hoursWorked, double payRate) {
     double basePay = hoursWorked * payRate;
     System.out.println( basePay + ", " + overtimePay(hoursWorked, payRate));
     return basePay + overtimePay(hoursWorked, payRate);
    }
    }
}
  • 예를들어 주중은 초과 근무시간만 추가수당으로 계산되고, 주말은 모든 근무시간이 추가 수당으로 계산 되야 하는 경우

  • 주중과 / 주말로 분기를 태우면 분기 하나가 더 추가 될 경우에 대한 위험 발생

  • 정책 enum 자료형을 선택하라

마무리 정리를 하자면,

  • enum 자료형은 int 상수에 비해 더 많은 장점을 가지고 있다.

  • enum은 코드 가독성이 높고, 안전하며, 더 강력

  • enum은 생성자나 멤버가 필요 없으나, 데이터 또는 그 관련된 메스드를 추가해서 기능을 향상시킬 수 있다.

  • 다른 동작의 상수별 구현을 위해서는 상수별 메서드를 구현하라.

  • 여러 enum 상수가 공통 기능을 이용해야 하는 경우, 정책 enum 패턴을 고려하라.

results matching ""

    No results matching ""