[Effective Java]인터페이스는 구현하는 쪽을 생각해 설계하라

클래스와 인터페이스, 일곱 번째 아이템

Posted by SungBeom on March 29, 2020 · 2 mins read

Intro

자바 8 전에는 기존 구현체를 깨뜨리지 않고는 인터페이스에 메소드를 추가할 방법이 없었으나, 자바 8에 와서 기존 인터페이스에 메소드를 추가할 수 있는 디폴트 메소드가 추가되었다. 디폴트 메소드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메소드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다. 인터페이스에 메소드를 추가하여 컴파일 오류가 날 일은 없어졌지만, 디폴트 메소드는 구현 클래스에 대해 아무것도 모른 채 합의 없이 무작정 삽입한다는 점에서 위험이 완전히 사라진 것은 아니다.

인터페이스 설계 시 주의할 점

자바 8에서는 람다를 활용하기 위해 핵심 컬렉션 인터페이스들에 다수의 인터페이스들이 추가되었다. 자바 라이브러리의 디폴트 메소드는 코드 품질이 높고 범용적이라 대부분 상황에서 잘 작동하지만, 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메소드를 작성하기란 어려운 법이다.

디폴트 메소드는 컴파일에 성공하더라도 기존 구현체에 런타임 오류를 일으킬 수 있다. 흔한 일은 아니지만, 나에게는 일어나지 않으리라는 보장도 없다.

기존 인터페이스에 디폴트 메소드로 새 메소드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 한다. 추가하려는 디폴트 메소드가 기존 구현체들과 충돌하지는 않을지 심사숙고해야 함도 당연하다.

한편, 디폴트 메소드는 인터페이스로부터 메소드를 제거하거나 기존 메소드의 시그니처를 수정하는 용도가 아님을 명심해야 한다. 이런 형태로 인터페이스를 변경하면 반드시 기존 클라이언트를 망가뜨리게 된다.

핵심은 디폴트 메소드라는 도구가 생겼더라도 인터페이스를 설계할 때는 여전히 세심한 주의를 기울여야 한다. 디폴트 메소드로 기존 인터페이스에 새로운 인터페이스를 추가하면 커다란 위험도 딸려 온다.

새로운 인터페이스라면 릴리즈 전에 반드시 테스트를 거쳐야 한다. 서로 다른 방식으로 최소한 세 가지는 구현해보고, 각 인터페이스의 인스턴스를 다양한 작업에 활용하는 클라이언트도 여러 개 만들어봐야 한다. 릴리즈하기 전에 결함을 찾아내는 것이 중요하며 인터페이스를 릴리즈한 후라도 결함을 수정하는 게 가능한 경우도 있겠지만, 절대 그 가능성에 기대서는 안 된다.


핵심 정리

자바 8에 인터페이스에 메소드를 추가하는 방식으로 디폴트 메소드가 도입되었으나, 신중하게 사용해야 한다. 모든 상황에서 불변식을 해치지 않는 티폴트 메소드를 작성하기란 어렵고, 오류를 낼 가능성도 있다. 따라서 인터페이스 설계할 때 세심한 주의를 기울여야 하며 반드시 테스트를 거쳐야 한다.