본문 바로가기
JAVA/Effective Java

item 21. 인터페이스는 구현하는 쪽을 생각해 설계하라

by Garonguri 2022. 5. 3.
728x90

Java 8 이후 디폴트 메서드를 사용할 수 있게 되었지만, 여전히 주의해야 할 점이 있다.

 

디폴트 메서드를 선언하면 해당 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 사용된다.

기존 인터페이스에 메서드를 추가할 수 있게 되었지만 모든 기존 구현체들과 연동되리라는 보장은 없다.

 

[ JAVA 8에서 Collection Interface에 추가된 removeIf 메서드 ]

default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    boolean removed = false;
    final Iterator<E> each = iterator();
    while (each.hasNext()) {
        if (filter.test(each.next())) {
            each.remove();
            removed = true;
        }
    }
    return removed;
}

- 현재 범용적으로 사용 하고는 있지만, 현존하는 모든 Collection 구현체와 잘 어울리는건 아니다.

ex) org.apache.commons.collections4.collection.SynchronizedCollection

- SynchroizedCollection을 사용했을 때 RemoveIf를 사용하게 되면 ConcurrentModificationException가 발생되거나 , 예상하지 못한 다른 결과를 보내준다.


이러한 문제의 예방법

- 구현한 인터페이스의 디폴트 메서드를 재정의하고, 다른 메서드에서는 디폴트 메서드(구현)를 호출하기 전에 필요한 작업을 수행하면 된다.

- 그러나 여전히 수정될 기회도 없고, 수정되지 않는 것들이 존재한다.

 

 


디폴트 메서드는 컴파일에 성공하더라도 기존 구현체에 런타임 오류를 일으킬 수 있다.

 그럼 어떻게 해야하나?

-> 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피하자.

-> 추가하려는 디폴트 메서드가 기존 구현체들과 충돌하지는 않을지 심사숙고하자.

 

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

 

디폴트 메서드라는 도구가 존재하지만, 인터페이스를 설계할 때는 여전히 세심한 주의를 기울여야 한다.

- Default Method로 기존 interface에 새로운 method를 추가하면 커다란 위험도 딸려온다.

 

새로운 인터페이스라면 릴리스 전에 반드시 테스트를 거쳐야 한다.

- 최소한 3가지로 구현을 해봐야 한다.

- 각 인터페이스의 인스턴스를 다양한 작업에 활용하는 클라이언트도 여러 개 만들어봐야 한다.

728x90

댓글