[Effective Java] 아이템 21 - 인터페이스는 구현하는 쪽을 생각해 설계하라
아이템 21 : 인터페이스는 구현하는 쪽을 생각해 설계하라
디폴트 메서드
- 자바 8에서 부터 기존 인터페이스에 메서드를 추가할 수 있게 되었다.
- 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다.
- 하지만 모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없다.
- 구현 클래스에 대해 아무것도 모른채 합의 없이 무작정 삽입될 뿐이다.
- 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어려운 법이다.
removeIf
- 주어진 predicate가 true를 반환하는 모든 웟노를 제거하는 메서드
- 아파치의 SynchronizedCollection 클래스는 지금도 활발히 관리되고 있지만, 책을 쓰는 시점엔 removeIf 메서드를 재정의하지 않고 있따.
- 이 클래스를 자바 8과 함께 사용한다면 모든 메서드 호출을 알아서 동기화해주지 못한다.
예방 방법
- 구현한 인터페이스의 디폴트 메서드를 재정의하고, 다른 메서드에서는 디폴트 메서드를 호출하기 전에 필요한 작업을 수행하도록 했다.
- SynchronizedCollection이 반환하는 package-private 클래스들은 removeIf를 재정의하고, 이를 호출하는 메서드들은 디폴트 구현을 호출하기 전에 동기화를 하도록 했다.
- 하지만 자바 플랫폼에 속하지 않은 제3의 기족 컬렉션 구현체들은 이런 언어 차원의 인터페이스 변화에 발맞춰 수정도리 기회가 없었으며 일부는 여전히 수정되지 않고 있다.
default 메서드의 런타임 오류
- default 메서드는 기존 구현체에 런타임 오류를 일으킬 수 있다.
- 자바 8은 컬렉션 인터페이스에 많은 default 메서드를 추가했고, 그 결과 기존에 짜여진 많은 자바 코드가 영향을 받았다.
- 기존 인터페이스에 default 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 한다.
- 추가하려는 default 메서드가 기존 구현체들과 충돌하지는 않을지 심사숙고해야 함은 당연하다.
새로운 인터페이스는?
- 새로운 인터페이스를 만드는 경우라면 표준적인 메서드 구현을 제공하는 데 아주 유용한 수단이다.
- 해당 인터페이스를 더 쉽게 구현해 활용할 수 있게끔 해준다.
정리
- default 메서드는 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아님을 명심해야 한다.
=> 이런 형태로 인터페이스를 변경하면 반드시 기존 클라이언트를 망가뜨리게 된다.
- default 메서드라는 도구가 생겨도 인터페이스를 설계 할 때는 여전히 세심한 주의를 기울여야 한다.
- 새로운 인터페이스라면 릴리스 전에 반드시 테스트를 거쳐야한다.
- 서로 다른 방식으로 최소한 3가지는 구현해봐야한다.
- 다양한 작업에 활용하는 클아이언트도 여러 개 만들어봐야 한다.
- 인터페이스를 릴리스한 후라도 결함을 수정하는 게 가능한 경우도 있겠지만, 절대 그 가능성에 기대서는 안 된다.