ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Item 21: Design interfaces for posterity
    독서/Effective Java 2021. 12. 26. 03:51

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

     

    인터페이스에 새로운 메서드를 추가한다면?

    Java 8 이전까지는 인터페이스에 메서드를 추가하기 위해서는 해당 인터페이스를 구체화하는 모든 클래스에서 이를 구현하고 있어야 했어서 기존 구현체를 깨트리지 않고는 인터페이스에 메서드를 추가할 방법이 존재하지 않았다.

    Java 8[JLS 9.4]부터는 "default method"라는 개념이 도입되어 구체화 클래스에서 따로 구현하지 않아도 default method를 사용하면 되지만, 그렇다고 해서 인터페이스에 메서드를 추가할 때의 위험이 사라지는 것은 아니다.

    디폴트 메서드를 사용한다고 해도 완벽하게 기존 클래스, 새로 구현할 클래스와 연동 가능하리란 보장은 없다.

    즉, 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 default method를 작성한다는 것은 어려운 일이다.

     

    Default Method의 예기치 못한 문제

    // Java 8의 Colleection Interface에 추가된 method
      default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        Iterator each = this.iterator();
    
        while(each.hasNext()) {
          if (filter.test(each.next())) {
            each.remove();
            removed = true;
          }
        }
    
        return removed;
      }

    해당 메서드는 filter 조건의 여부(true)에 따라 Collection 내의 원소를 제거한다. 해당 예시가 굉장히 범용적으로 구성되었지만, 모든 Collection 구현체와 어우러지는 것은 아닌데, 대표적으로는 apache.commons.collections4.collection.SynchronizedCollection가 있다.

    (해당 글을 작성하는 시간에는 이미 SynchronizedCollection에 정의되어 있다.)

     @Override
        public boolean removeIf(final Predicate<? super E> filter) {
            synchronized (lock) {
                return decorated().removeIf(filter);
            }
        }

    해당 클래스의 경우 책에서의 작성 시점에서는 내부에 removeIf가 구현되어 있지 않았었기 때문에 default method를 호출하는 순간 lock에 대한 보장을 할 수 없거나, ConcurrentModificationException 예외가 발생했었다. Default method가 외부 클래스의 작동을 보장하지 못한 것이다.

    또한, Default Method는 컴파일에 성공하더라도 런타임에서 오류를 일으킬 수 있다.

     

    정리

    • 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우만 해야 한다.
      • 해야 한다면 기존 구현체들과의 충돌에 대한 검증을 수행해야 한다.
    • 디폴트 메서드는 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아니다.
    • 인터페이스를 설계할 때에는 세심한 주의를 기울여야 한다.
    • 새로운 인터페이스라면 릴리즈 전에 반드시 테스트하자.
      • 최소한 3가지 방법의 구현체를 구현해보자.
      • 클라이언트도 여러 개 만들어보자.

    댓글

Designed by Tistory.