[Effective Java 3/E] ITEM 38. 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라.

대연.

·

2021. 3. 28. 17:50

Effective Java 표지. Source : https://blog.insightbook.co.kr/

*알림 : *
Effective Java 3판은 Java 9까지 도입된 언어적 기능을 중심으로 서술되어 있습니다. 10버젼 이후의 Java 개발을 하시는 분들은 우회적인 접근법 대신 Java 언어 내 새로 도입된 기능이 더 간결하고 좋을 수 있습니다.

해당 포스팅은 SSAFY 내 책읽기 스터디의 활동을 통해 작성된 포스팅입니다.
https://github.com/kjsu0209/JavaBook
https://medium.com/javabook

 

kjsu0209/JavaBook

책읽기 스터디. Contribute to kjsu0209/JavaBook development by creating an account on GitHub.

github.com

 

JavaBook – Medium

Documentation space of our book study.

medium.com

 

 

Enum type은 확장을 할 수 없다. OOP의 상속의 시점으로 본다면, 확장한 타입들의 원소는 상위 타입의 원소가 되지만, 그 반대는 성립하지 않는다. 순회할 방법도 마땅치 않다. 설계와 구현의 난이도도 올라갈 것이다.

그러나 Enum 타입은 인터페이스를 구현할 수 있다.

예제 1 : 연산 코드(Operation Code)

// 인터페이스 정의
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;
    }
}

Enum 타입인 BasicOperation*은 확장할 수 없지만, *Operation 인터페이스는 확장이 가능하다. 사칙연산 뿐 아니라 mod 연산과 exp 지수연산을 추가하고 싶다고 가정하자. Operation 인터페이스를 확장해 구현하기만 하면 된다.

예제 1-1 : 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 뿐 아니라 ExtendedOperation도 인터페이스를 통해 접근할 수 있다.

예제 2 : 확장된 Enum 타입을 인터페이스로 접근하기

public static void main(String[] args) {
        double x = Double.parseDouble(args[0]);
        double y = Double.parseDouble(args[1]);
        test(Arrays.asList(ExtendedOperation.values()), x, y);
    }
    private 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));
    }
}

ExtendedOperation.values()*는 상수의 배열을 반환한다. 앞서 다뤘던 아이템에서 보았듯이 가능하면 배열보다는 List를 사용하길 권장하므로, *Arrays.asList() 메서드로 배열을 리스트로 변환한다.

한정적 타입을 통해 Operation을 확장한 무언가를 담고있는 Collection을 test 메서드에서 인자로 받는다.

확장한 타입의 코드 중복작성을 줄이는 테크닉

그러나 열거타입끼리 상속을 구현할 수 없는 문제는 여전하다. 그러나 확장한 Enum 타입끼리 많은 로직을 공유해야 한다면?

  1. 별도의 Helper class 작성
  2. Static helper method로 분리
  3. 인터페이스의 default 메서드

0개의 댓글