You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
마지막으로, 그럼 이 방법은 모든 면에서 완벽할까? 그건 또 아니다. 열거 타입끼리는 구현을 상속할 수 없기 때문에 발생하는 (사소한) 문제가 존재한다. 이런 경우에는 아래와 같은 방법으로 해결할 수 있다.
아무런 상태도 의존하지 않는 경우, 디폴트 구현으로 인터페이스에 추가한다.
공유 기능이 많다면, 별도의 도우미 클래스나 정적 도우미 메서드를 분리한다.
3️⃣ 명명패턴 보다는 애너테이션을 사용해라.
💡 애너테이션으로 할 수 있는 일을 명명 패턴으로 처리할 이유는 없다.
명명 패턴은, 변수나 함수의 이름을 일관된 방식으로 작성하는 패턴 을 말한다. 교재에서는 명명 패턴의 3가지 단점을 제시하며 명명패턴보다 애너테이션을 사용하는 것이 좋다고 말한다.
오타가 나면 안된다.
올바른 프로그램 요소에서만 사용되리라 보증할 방법이 없다.
프로그램 요소를 매개변수로 전달할 마땅한 방법이 없다.
오타가 난 메서드를 테스트 하지 않고 지나쳐서 성공했다고 오해하거나(1), 메서드 이름이 아닌 클래스 이름을 전달해서 테스트가 수행되지 않거나(2), 특정 예외를 던져야 성공하는 테스트에서 원하는 예외를 전달해줄 방법이 없는(3) 등의 문제 상황이 발생할 수 있다.
그리고 이런 문제들은 애너테이션 으로 해결할 수 있다.
importjava.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test{
}
교재에 있는 가장 기본적인 마커 애너테이션 @Test 를 정의한 모습이다. 이 안에 @Retention 과 @Target 은 메타 애너테이션이다.
마커 애너테이션 : 아무 매개변수 없이 단순히 대상에 마킹하는 애너테이션
메타 애너테이션 : 애너테이션 선언에 다는 애너테이션
두 가지 메타 애너테이션에 대해 먼저 살펴보면, @Retention 은 애너테이션이 실제로 적용되고 유지되는 범위를 지정할 수 있으며, 가능한 값은 다음과 같다.
값
설명
RetentionPolicy.RUNTIME
컴파일 이후에도 JVM에 의해 계속 참조가 가능. 주로 리플렉션이나 로깅에 사용
RetentionPolicy.CLASS
컴파일러가 클래스를 참조할 때까지 유효
RetentionPolicy.SOURCE
컴파일 전까지 유효. 컴파일 이후에는 사라짐
@Target 은 애너테이션이 어디에 적용될지를 결정하며, 가능한 값은 다음과 같다.
값
설명
ElementType.PACKAGE
패키지 선언
ElementType.TYPE
타입 선언
ElementType.ANNOTATION_TYPE
애너테이션 선언
ElementType.CONSTRUCTOR
생성자 선언
ElementType.FIELD
필드 선언
ElementType.LOCAL_VARIABLE
지역 변수 선언
ElementType.METHOD
메서드 선언
ElementType.PARAMETER
매개변수 선언
ElementType.TYPE_PARAMETER
매개변수 타입 선언
ElementType.TYPE_USE
타입이 사용되는 곳에 선언
추가로, 필요한 매개변수 타입을 애너테이션 타입에 지정해줄 수도 있다.
importjava.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest{
Class<? extendsThrowable> value(); // 모든 예외를 수용
}
이 경우에는, 애너테이션을 활용할 때 필요한 예외를 지정해주면 된다. 지정한 예외가 발생하지 않거나 다른 예외가 발생하는 경우에는 테스트가 실패하고, 지정한 예외가 발생하는 경우에만 테스트가 성공할 것이다.
만약, 여러 개의 예외를 명시하고 싶다면 매개변수타입을 Class 객체의 배열로 수정하면 된다.
importjava.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest{
Class<? extendsThrowable>[] value();
}
활용할 때는 필요한 예외들을 중괄호로 감싸서 지정하면 된다. 자바 8부터는 @Repeatable 메타 애너테이션을 통해 여러 개의 값을 받는 애너테이션을 만들 수도 있다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(ExceptionTestContainer.class)
public @interface ExceptionTest{
Class<? extendsThrowable> value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTestContainer{
ExceptionTest[] value();
}
이 때 주의할 점은.
@Repeatable 을 단 애너테이션을 반환하는 컨테이너 애너테이션을 정의하고, @Repeatable에 이 컨테이너 애너테이션의 class 객체를 매개변수로 전달해야 한다.
컨테이너 애너테이션은 내부 에너테이션 타입의 배열을 반환하는 value 메서드를 정의해야 한다.
컨테이너 애너테이션 타입에는 적절한 보존 정책(@Retention) 과 적용 대상(@Target) 을 명시해야 한다.
또한 활용할 때에도, isAnnotationPresent 로 애너테이션 여부를 검사할 때, 컨테이너 애너테이션과 내부 애너테이션을 모두 확인해야 한다는 점도 주의가 필요하다. 단, getAnnotationsByType 은 컨테이너 애너테이션과 내부 애너테이션을 구분하지 않는다.
🍃 결론
열거 타입을 확장하고 싶을 때는 인터페이스를 활용하고, 이왕이면 애너테이션을 사용해서 코딩하자 !
section: 6장
🍵 서론
다민이를 위한 이번 이슈 3줄 요약.
🌒 본론
1️⃣ 열거 타입 자체는 확장할 수 없다.
이미 누군가가 열거 타입이 뭔지, 장점이 뭐가 있는지 설명을 해줬을 것이다. 하지만, 열거 타입은 확장을 할 수 없다는 단점이 있다. 사실 단점도 아닌게, 열거 타입을 확장하는 건 좋지 않은 생각이다.
그 이유는,
그래서 대부분의 경우에는 열거 타입의 확장이 필요하지 않으나, 교재에서도 제시한
연산 코드
는 확장이 어울리는 열거 타입이다. 기본으로 제공하는 연산 외에 사용자가 연산을 추가하고 싶다면 확장이 필요하다. 그렇다면 어떻게 확장할 수 있을까?아래 코드는
타입 안전 열거 패턴
이다. 타입 안전 열거 패턴은 모든 면에서 열거 타입보다 좋지 않지만, 확장이 가능하다는 점 하나가 우수하다.그렇다면, 확장이 필요한 연산 코드 같은 경우 모든 단점을 감수하고
타입 안전 열거 패턴
을 사용해야 할까? 답은 아니다. 다행히도 우리에게 익숙한인터페이스
를 사용해서 확장의 효과를 낼 수 있다.2️⃣ 확장하고 싶다면 인터페이스를 사용해라.
연산 코드용 인터페이스를 정의하고, 열거 타입이 해당 인터페이스를 구현하도록 한다.
여기서 확장이 필요하다면 ? 인터페이스를 구현하는 또 다른 열거 타입을 만들면 된다!
기존에
BasicOperation
이 아닌Operation
을 사용하도록 잘 작성이 되어 있었다면, 아무런 변경 없이 확장한 열거 타입을 사용할 수 있다. 또한, 해당 방식처럼 인터페이스를 사용한다면 별도의 추상 메서드를 정의할 필요가 없다는 점도 장점이다.앞서, 열거 타입에서 확장을 고려하는 건 좋지 못한 생각이라고 한 이유 중 하나가 "기반 타입과 확장 타입 원소를 모두 순회할 방법이 없다"는 점이었다. 인터페이스를 사용하면 이 점도 해결할 수 있다.
마지막으로, 그럼 이 방법은 모든 면에서 완벽할까? 그건 또 아니다. 열거 타입끼리는 구현을 상속할 수 없기 때문에 발생하는 (사소한) 문제가 존재한다. 이런 경우에는 아래와 같은 방법으로 해결할 수 있다.
3️⃣ 명명패턴 보다는 애너테이션을 사용해라.
명명 패턴은, 변수나 함수의 이름을 일관된 방식으로 작성하는 패턴 을 말한다. 교재에서는 명명 패턴의 3가지 단점을 제시하며 명명패턴보다 애너테이션을 사용하는 것이 좋다고 말한다.
오타가 난 메서드를 테스트 하지 않고 지나쳐서 성공했다고 오해하거나(1), 메서드 이름이 아닌 클래스 이름을 전달해서 테스트가 수행되지 않거나(2), 특정 예외를 던져야 성공하는 테스트에서 원하는 예외를 전달해줄 방법이 없는(3) 등의 문제 상황이 발생할 수 있다.
그리고 이런 문제들은
애너테이션
으로 해결할 수 있다.교재에 있는 가장 기본적인 마커 애너테이션
@Test
를 정의한 모습이다. 이 안에@Retention
과@Target
은 메타 애너테이션이다.두 가지 메타 애너테이션에 대해 먼저 살펴보면,
@Retention
은 애너테이션이 실제로 적용되고 유지되는 범위를 지정할 수 있으며, 가능한 값은 다음과 같다.@Target
은 애너테이션이 어디에 적용될지를 결정하며, 가능한 값은 다음과 같다.추가로, 필요한 매개변수 타입을 애너테이션 타입에 지정해줄 수도 있다.
이 경우에는, 애너테이션을 활용할 때 필요한 예외를 지정해주면 된다. 지정한 예외가 발생하지 않거나 다른 예외가 발생하는 경우에는 테스트가 실패하고, 지정한 예외가 발생하는 경우에만 테스트가 성공할 것이다.
만약, 여러 개의 예외를 명시하고 싶다면 매개변수타입을 Class 객체의 배열로 수정하면 된다.
활용할 때는 필요한 예외들을 중괄호로 감싸서 지정하면 된다. 자바 8부터는
@Repeatable
메타 애너테이션을 통해 여러 개의 값을 받는 애너테이션을 만들 수도 있다.이 때 주의할 점은.
@Repeatable
을 단 애너테이션을 반환하는 컨테이너 애너테이션을 정의하고,@Repeatable
에 이 컨테이너 애너테이션의 class 객체를 매개변수로 전달해야 한다.@Retention
) 과 적용 대상(@Target
) 을 명시해야 한다.또한 활용할 때에도,
isAnnotationPresent
로 애너테이션 여부를 검사할 때, 컨테이너 애너테이션과 내부 애너테이션을 모두 확인해야 한다는 점도 주의가 필요하다. 단,getAnnotationsByType
은 컨테이너 애너테이션과 내부 애너테이션을 구분하지 않는다.🍃 결론
열거 타입을 확장하고 싶을 때는 인터페이스를 활용하고, 이왕이면 애너테이션을 사용해서 코딩하자 !
reference
The text was updated successfully, but these errors were encountered: