카테고리:

업데이트:

1. 들어가기

타입 안전 열거 패턴은 클래스를 이용해 private 생성자로 만들어 최초 정의된 객체만 참조하는 패턴으로

다음과 같이 사용할 수 있습니다.

  public class Symbol {
    private final String type;

    private Symbol(String type){
      this.type = type;
    }

    public String toString(){
      return type;
    }
  }
  public static final Symbol Terminal = new Symbol("Terminal");
  public static final Symbol Process = new Symbol("Process");
  public static final Symbol Decision = new Symbol("Decision");

하지만, 우리가 배운 열거 타입은 단 한 가지 예외를 제외하고 타입 안전 열거 패턴보다 우수한데

어떤 예외가 있는지 알아보겠습니다.

2. 열거 타입의 한 가지 예외

타입 안전 열거 패턴은 열거한 값들을 그대로 가져와서 값을 추가해 확장할 수 있습니다.

하지만, 열거 타입은 그럴 수 없습니다.

사실 대부분 상황에서 열거 타입을 확장하는 것은 좋지 않지만,

연산 코드와 같은 예시는 확장 연산을 추가할 수 있도록 열어줘야할 때가 있습니다.

다행히 열거 타입으로 확장할 수 있는 방법이 있습니다.

3. 열거 타입의 한 가지 예외 해결법

열거 타입 자체는 확장할 수 없지만, 인터페이스를 통해 확장을 가능하도록 만들 수 있습니다.

  public interface Operation {
    double apply(double x, double y);
  }
/* 기본 열거 타입 */
  public enum BasicOperation implements Operation {
    PLUS("+") {
      public double apply(double x, double y) { return x + y; }
    },
    MINUS("-") {
      public double apply(double x, double y) { return x - y; }
    },
    TIMES("*") {
      public double apply(double x, double y) { return x * y; }
    },
    DIVIDE("/") {
      public double apply(double x, double y) { return x / y; }
    };

    private final String symbol;

    BasicOperation(String symbol) {
      this.symbol = symbol;
    }

    @Override public String toString() {
      return symbol;
    }
  }

연산 타입을 Operation 인터페이스로 지정해서 사용하면

Operation 인터페이스를 구현한 또 다른 열거 타입을 정의할 수 있습니다.

/* 새로 확장한 열거 타입 */
  public enum ExtendedOperation implements Operation {
    EXP("^") {
      public double apply(double x, double y) {
        return Math.pow(x, y);
      }
    },
    REMAINDER("%") {
      public double apply(double x, double y) {
        return x % y;
      }
    };

    private final String symbol;

    ExtendedOperation(String symbol) {
      this.symbol = symbol;
    }

    @Override public String toString() {
      return symbol;
    }
  }

그리고 그 새로운 열거 타입은 BasicOperation 열거 타입을 대체할 수 있습니다.

새로운 열거 타입을 사용하기 위해서는 Operation 인터페이스만을 허용해야 하는데

두 가지 방법 중 하나를 선택할 수 있습니다.

  1. 한정적 타입 토큰 역할을 하는 Class 리터럴을 사용한 방법

     static <T extends Enum<T> & Operation> void test(Class<T> opEnumType, double x, double y) {
       for (Operation op : opEnumType.getEnumConstants())
         System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
     }
    
  2. 한정적 와일드카드 타입을 넘기는 방법

     static void test(Collection<? extends Operation> opSet, double x, double y) {
       for (Operation op : opSet)
         System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
     }
    

4. 정리

타입 안전 열거 패턴과 열거 타입을 비교했을 때 대부분 열거 타입이 우수하지만

그 자체로는 확장이 불가능한 단점이 있었습니다.

이를 해결하기 위해서는 인터페이스와 해당 인터페이스를 구현하는 열거 타입을 통해

확장과 같은 효과를 낼 수 있습니다.

            
              📕 개인 기록용 블로그입니다.
              😊 오타나 잘못된 정보가 있을 경우 댓글이나 메일로 말씀해주시면 바로 수정하겠습니다! 😊
          

댓글남기기