맞는데 왜 틀릴까..?

Java/Effective Java

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

안도일 2023. 5. 3. 23:20

디폴트 메서드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다. 이처럼 자바 8 이후에 자바에도 기존 인터페이스에 메서드를 추가하는 길이 열렸지만 모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없다.

 

자바 8 이전의 모든 클래스는 "현재 인터페이스에 새로운 메서드가 추가될 일이 없다"라고 생각해 설계되었기 때문이다.

디폴트 메서드는 구현 클래스에 대해 아무것도 모른 채 합의 없이 무작정 '삽입' 될 뿐이다.

따라서 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기는 어렵다.

 

디폴트 메서드로 인한 피해 예시

아파치의 SynchronizedCollection 클래스는 현재에도 removeIf 메서드를 오버라이딩하고 있지 않은데, 이 클래스를 자바 8과 함께 사용해 removeIf의 디폴트 구현을 물려받게 된다면 SynchronizedCollection의 제 기능을 할 수 없게 된다.

 


인터페이스를 설계할 때 주의할 점

 

 

  1. 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피하자.
  2. 추가하려는 디폴트 메서드가 기존 구현체들과 충돌하지 않을지 심사숙고하자.
  3. 디폴트 메서드는 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아니다.
  4. 새로운 인터페이스를 만드는 경우라면 릴리스 전에 반드시 테스트를 거치자.

 

디폴트 메서드는 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아니다.

디폴트 메서드는 본래 인터페이스를 확장하면서 기존 구현체의 호환성을 유지하기 위한 목적으로 추가된 기능이다. 디폴트 메서드를 사용하여 인터페이스에 새로운 기능을 추가하면, 기존에 인터페이스를 구현하는 클래스들은 추가된 기능을 구현하지 않아도 그대로 사용할 수 있다. 이러한 특징으로, 디폴트 메서드는 기존 인터페이스의 시그니처를 수정하거나 인터페이스에서 메서드를 제거하는 것과는 전혀 다른 목적으로 사용된다.

인터페이스에서 메서드를 제거하거나 시그니처를 수정하는 것은 인터페이스를 구현하는 클래스들에게 영향을 미치는 변경사항이며, 이는 호환성 문제를 불러일으킬 수 있다.