item 38 : 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라
열거 타입을 확장 가능하게 만들고자 할 때, 자바에서는 Enum
자체의 확장은 허용되지 않는다.
대신 인터페이스와 열거 타입을 함께 활용하여 열거 타입을 확장하는 것과 유사한 효과를 낼 수 있다. 이를 통해 열거 타입의 이점을 유지하면서도 필요한 경우 확장 가능한 열거 타입과 같은 기능을 구현할 수 있다.
확장 가능 열거 타입을 위한 인터페이스 사용
먼저, 인터페이스를 이용해 열거 타입의 기본 동작을 정의한다. 그리고 열거 타입이 이 인터페이스를 구현하여 기본 기능을 제공하도록 설계한다.
1. 연산 인터페이스 Operation
Operation
기본적으로 제공하는 연산은 Operation
이라는 인터페이스를 통해 정의된다.
Operation
인터페이스는 연산을 나타내는 추상 메서드apply(double x, double y)
를 제공한다,이를 통해 연산을 수행하는 열거 타입이 추가될 때마다
apply
메서드를 각기 다른 방식으로 구현할 수 있게 된다.
2. BasicOperation
열거 타입
BasicOperation
열거 타입기본 연산 기능을 제공하는 열거 타입 BasicOperation
을 정의한다. 각 열거 상수는 Operation
인터페이스를 구현하여 연산을 수행한다.
BasicOperation
은Operation
인터페이스를 구현하며,PLUS
,MINUS
,TIMES
,DIVIDE
의 기본 연산을 정의한다.apply
메서드는Operation
인터페이스의 메서드로서 열거 상수마다 다르게 정의된다.
3. ExtendedOperation
열거 타입
ExtendedOperation
열거 타입기본 연산에 더해 새로운 연산을 정의하고자 할 때는 또 다른 열거 타입을 정의하여 Operation
인터페이스를 구현할 수 있다.
ExtendedOperation
은 기존 연산 외에 추가 연산(거듭제곱(EXP)와 나머지(REMAINDER))을 구현한다.기본 열거 타입
BasicOperation
을 확장한 것은 아니지만,Operation
인터페이스를 구현함으로써 기존 연산과 같은 방식으로 사용할 수 있다.
4. 확장 가능 열거 타입의 활용 예
기존 연산과 새로운 연산을 모두 사용할 수 있도록 Operation
인터페이스를 기반으로 처리하는 메서드를 작성한한다.
test
메서드는Collection<? extends Operation>
타입을 받아,Operation
인터페이스를 구현한 열거 타입을 모두 처리할 수 있다.test(Arrays.asList(BasicOperation.values()), x, y);
는BasicOperation
의 연산을 테스트하고,test(Arrays.asList(ExtendedOperation.values()), x, y);
는ExtendedOperation
의 연산을 테스트한다.
5. Class<T>
를 이용한 확장성 제공
Class<T>
를 이용한 확장성 제공연산 인터페이스와 열거 타입을 Class<T>
로 받아 확장된 열거 타입의 모든 원소를 순회하는 방식으로도 사용 가능하하다.
Class<T> opEnumType
에ExtendedOperation.class
를 넘기면 확장된 연산을 포함해 열거 타입의 모든 원소를 사용할 수 있습.<T extends Enum<T> & Operation>
으로 제약을 설정하여Enum
이면서Operation
을 구현한 타입만 허용한다.
요약
이 패턴을 사용하면 기존 열거 타입을 수정하지 않고도 확장된 연산을 추가할 수 있다. Operation
인터페이스를 통해 확장 가능성을 제공하면서도 열거 타입의 장점을 유지하는 이점이 있다.
타입 안전성을 유지하며 새로운 연산을 추가할 수 있다.
코드 중복을 줄이고, 기본 열거 타입과 확장된 열거 타입의 사용 방식을 동일하게 유지한다.
EnumMap이나 EnumSet을 사용할 수는 없지만,
Operation
인터페이스를 사용해 기존 코드를 그대로 확장할 수 있다.
이 패턴은 주로 java.nio.file.LinkOption
등이 적용된 방식으로, 인터페이스와 열거 타입을 결합하여 확장 가능한 열거 타입을 구현하는 효과를 제공한다.
핵심 정리
열거 타입 자체는 확장할 수 없지만, 인터페이스와 그 인터페이스를 구현하는 기본 열거 타입을 함께 사용해 같은
효과
를 낼 수 있다.
이렇게 하면 클라이언트는 이 인터페이스 를 구현해 자신만의 열거 타입혹은 다른 타입을 만들 수 있다.
API가 기본 열거 타입을 직접 명시하지 않고 인터페이스 기반으로 작성되었다면 기본 열거 타입의 인스 턴스가 쓰이는 모든 곳을 새로 확장한 열거 타입의 인스턴스로 대체해 사용할 수 있다.
Last updated