Item 38. Extended Enum

확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라.

열거 타입에 단점 중 하나는 확장이 불가능하다는 것이다. 열거 타입을 확장하는 방법은 없지만, 인터페이스를 사용하면 비슷한 효과를 낼 수 있다. 대부분의 상황에서는 열거 타입을 확장하는 것이 좋지 않지만, 확장할 수 있는 열거 타입이 필요하다면 인터페이스를 사용하자. 대표적인 예로 연산 코드를 나타내는 열거 타입이 있다.

interface Operation {
    double apply(double x, double y);
}

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 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;
    }
}

인터페이스의 Operation을 확장하여, 이 인터페이스를 연산의 타입으로 사용한 열거 타입 BasicOperation을 정의했다. 이렇게 하면 다음과 같은 이점을 얻을 수 있다.

  • apply 메서드가 인터페이스에 선언되어 있어 별도로 추상 메서드를 선언할 필요가 없음

  • 인터페이스를 구현한 열거 타입을 만들어 연산 코드를 쉽게 추가 및 대체 가능

아래 코드는 인터페이스를 확장한 확장된 연산 코드를 적용한 예시이다.

import java.util.Collections;

class Main {
    public static void main(String[] args) {
        double x = 2.0;
        double y = 4.0;
        test1(BasicOperation.class, x, y);
        test1(ExtendedOperation.class, x, y);
        test2(Arrays.asList(ExtendedOperation.values()), x, y);
    }

    /**
     * @param opEnumType: class 리터럴을 넘겨 확장된 열거 타입의 Class 객체를 넘겨 확장된 연산들을 알려줌
     * @param x
     * @param y
     * @param <T>: T extends Enum<T> & Operation -> T는 열거 타입이면서 Operation 인터페이스를 구현한 타입
     */
    private 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));
        }
    }

    /**
     * @param opSet: 한정적 와일드 카드 타입을 사용하여, 확장된 열거 타입의 인스턴스 집합을 받음
     * @param x
     * @param y
     */
    private static void test2(Collections<? 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));
        }
    }
}

Last updated

Was this helpful?