[EFFECTIVE JAVA] ITEM 41, 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라
Posted by
iheese
on October 13, 2023 ·
3 mins read
ITEM 41, 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라
마커 인터페이스(Marker Interface)
아무 메서드도 담고 있지 않고, 단지 자신을 구현하는 클래스가 특정 속성을 가짐을 표시하는 인터페이스
EX) Serializable : 자신을 구현한 클래스의 인스턴스는 ObjectOutputStream을 쓸 수 있다고, 즉 직렬화할 수 있다고 알려준다.
마커 인터페이스가 마커 애너테이션보다 나은 점
마커 인터페이스는 이를 구현한 클래스의 인스턴스를 구분하는 타입으로 쓸 수 있으나, 마커 애너테이션은 그렇지 않다.
마커 애너테이션을 사용했다면 런타임에야 발견될 오류를 마커 인터페이스는 타입이므로 컴파일에 잡을 수 있다.
BAD EX) OBjectOutputStrema.writeObject 메소드는 인수로 받은 객체가 Serialzable을 구현하였을 것이라고 가정하지만 Serialzable이 아닌 Object 타입을 받게 설계되었다. 직렬화 불가능한 객체를 넘겨도 런타임에야 문제를 확인할 수 있다. 마커 인터페이스를 사용하는 이유인 컴파일 타임 오류 검출의 이점을 살리지 못했다.
자바의 직렬화는 Serialzable 마커 인터페이스를 보고 직렬화할 수 있는 대상인지 확인한다.
적용 대상을 더 정밀하게 지정할 수 있다.
적용 대상(@Target)을 ElementType.TYPE으로 선언한 애너테이션은 모든 타입(클래스, 인터페이스, 열거 타입, 애너테이션)에 달 수 있다. 이는 부착할 수 있는 타입을 세밀하게 제한하지 못한다는 뜻이다.
특정 인터페이스를 구현한 클래스에만 적용하고 싶은 마커가 있다고 하면, 마커를 인터페이스로 정의했다면 마킹하고 싶은 클래스에서만 인터페이스(인터페이스라면 확장)를 구현하면 된다. 이는 자동으로 인터페이스의 하위 타입을 보장하는 것이다.
Set 인터페이스
Set은 Collection의 하위 타입에만 적용할 수 있다.
Collection이 정의한 메소드 외에는 새로 추가한 것이 없다.
Set을 마커 인터페이스로 생각하지 않는 이유는 add, equals, hashCode 등 메소드 몇 개의 규약을 살짝 수정했기 때문이다.
특정 인터페이스의 하위 타입에만 적용할 수 있으며, 아무 규약에도 손대지 않은 마커 인터페이스는 충분히 있음직하다.
객체의 특정 부분을 불변식으로 규정
그 타입의 인스턴스는 다른 클래스의 특정 메소드가 처리할 수 있는다는 사실을 명시하는 용도
EX) Serialzable 인터페이스가 ObjectOutputStream이 처리할 수 있는 인스턴스임을 명시하듯이
마커 애너테이션이 마커 인터페이스보다 나은 점
거대한 애너테이션 시스템의 지원을 받는다.
애너테이션을 적극 활용하는 프레임워크에 마커 애너테이션을 쓰는 쪽이 일관성에 좋을 수 있다.
사용해야할 때를 구분해보자
마커 애너테이션
클래스와 인터페이스 외의 프로그램 요소들(모듈, 패키지, 필드, 지역변수 등)에 마킹해야 할 때 애너테이션을 쓸 수 밖에 없다.
마커를 인터페이스나 클래스에 적용할 때, 이 마킹된 객체를 매개변수로 받는 메소드를 작성할 일이 절대 없다면 마커 애너테이션를 사용하는 것이 좋다.
애너테이션을 활발히 활용하는 프레임워크라면 마커 애너테이션이 나을 것이다.
마커 인터페이스
마커를 인터페이스나 클래스에 적용할 때, 이 마킹된 객체를 매개변수로 받는 메소드를 작성할 일이 있다면 마커 인터페이스를 사용해야 한다.