Skip to content

Latest commit

 

History

History
80 lines (68 loc) · 3.83 KB

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

File metadata and controls

80 lines (68 loc) · 3.83 KB

디폴트 메서드를 너무 믿지 말고, 인터페이스를 설계할 때는 세심한 주의를 기울여야 한다

Java8 이전

  • 기존 구현체를 깨뜨리지 않고는 인터페이스에 메서드를 추가할 수 있는 방법이 없었다.
  • "현재 인터페이스에 새로운 메서드가 추가될 일은 영원히 없다"
  • 요구사항 추가 -> 인터페이스에 메서드 추가 -> 모든 구현체 클래스 변경

Java8 이후
기존 인터페이스에 메서드를 추가할 수 있는 디폴트 메서드가 추가되었다.

핵심

  • 디폴트 메서드는 완전한 것이 아니다. 기존 클래스에 여러 문제를 야기할 수 있다.
  • 디폴트 메서드는 꼭 필요한 경우가 아니면 사용을 피해라.
  • 인터페이스를 설계할 때는 여전히 세심한 주의를 기울여야 한다.
  • 인터페이스를 설계할 때는 추후 변경사항이 발생하지 않도록 릴리즈 전 많은 테스트 과정을 거쳐야한다.

디폴트 메서드(Defautl Method)

디폴트 메서드는 인터페이스에 있는 구현 메서드를 의미한다.

  • 메서드 앞에 deault 에약어가 붙는다.
  • 구현부 {}가 있어야 한다.

다음은 List 인터페이스의 디폴트 메서드와 추상 메서드이다.

// 디폴트 메서드
default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}
 
// 추상 메서드
void clear();

디폴트 메서드.. 마냥 좋은 것이 아니다

장점

  • 기존 추상 메서드와 다르게 인터페이스 안에서 디폴트 구현을 지정할 수 있다.
  • 디폴트 메서드를 재정의하지 않은 모든 클래스에서는 디폴트 구현을 사용하며, 재정의해 사용할 수도 있다.

단점

  • 디폴트 메서드는 구현 클래스에 대해 아무것도 모른 채 합의 없이 무작정 삽입될 뿐이므로 주의해야한다.
  • Java8에서는 람다를 제공하기 위해 핵심 컬렉션 인터페이스들에 다수의 디폴트 메서드들을 추가하였다.
    • 코드 품질이 높고 범용적이라 대부분의 상황에서 잘 작동한다.
    • 하지만 모든 상황을 커버할 수는 없다.

Java8의 Collection 인터페이스에 추가된 디폴트 메서드

public interface Collection<E> extends Iterable<E> {
    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;
    }
}

org.apache.commons.collections4.collection.SynchronizedCollection와의 호환 문제

  • SynchronizedCollection은 동기화를 제공해 멀티 스레드 환경에서 안정성을 보장해준다.
  • 하지만 removeIf()를 재정의하고 있지 않다.
  • removeIf()는 동기화에 관해 아무것도 모르므로 멀티 스레드 환경에서 실행하다 보면 예기치 못한 결과를 야기할 수 있게된다. (최신 버전에서는 이슈 해결)

자바 플랫폼에서는 다음과 같은 조치를 취했다.

  • 구현한 인터페이스의 디폴트 메서드를 재정의한다.
  • 다른 메서드에서는 디폴트 메서드를 호출하기 전에 필요한 작업을 수행하도록 했다.

하지만 그렇다고 해서 모든 오류를 잡아낼 수 있는 것이 아니며, 컴파일에 성공하더라도 기존 구현체에 런타임 오류를 일으키는 등 다양함 문제를 야기할 수 있다. 🥲

Ref.