Skip to content

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

@heon118

Description

@heon118

Chapter : 4. 클래스와 인터페이스

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

Assignee : heon118


🍑 서론

  • 자바 8 이전에는 기존 구현체를 깨뜨리지 않고는 인터페이스에 메서드를 추가할 방법이 없었다.
    • 인터페이스에 메서드를 추가하면 보통은 컴파일 오류가 나는데, 추가된 메서드가 기존 구현체에 존재할 가능성이 아주 낮기 때문

🍑 본론

default method

image

  • 자바 8 이후부터 기존 인터페이스에 메서드를 추가할 수 있도록 디폴트 메서드 추가
  • 디폴트 메서드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다.
    • 디폴트 메서드는 구현 클래스에 대해 아무것도 모른 채 합의 없이 무작정 '삽입'될 뿐이므로 주의
  • 자바 8에서는 핵심 컬렉션 인터페이스들에 다수의 디폴트 메서드가 추가되었다.
    • 주로 람다를 활용하기 위함.
  • 자바 라이브러리의 디폴트 메서드는 코드 품질이 높고 범용적이라 대부분의 상황에서 잘 작동하지만, 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하는 것은 어렵다.
interface MyInterface { 
    default void printHello() {
    	System.out.println("Hello World"); 
        } 
} 

class MyClass implements MyInterface {} 

public class DefaultMethod { 
    public static void main(String[] args) { 
    	MyClass myClass = new MyClass(); 
        myClass.printHello(); //실행결과 Hello World 출력 
    } 
}

...(중략) ... 바로 "하위 호환성"때문이다. 예를 들어 설명하자면, 여러분들이 만약 오픈 소스코드를 만들었다고 가정하자. 그 오픈소스가 엄청 유명해져서 전 세계 사람들이 다 사용하고 있는데, 인터페이스에 새로운 메소드를 만들어야 하는 상황이 발생했다. 자칫 잘못하면 내가 만든 오픈소스를 사용한 사람들은 전부 오류가 발생하고 수정을 해야 하는 일이 발생할 수도 있다. 이럴 때 사용하는 것이 바로 default 메소드다. (자바의 신 2권) default method 예제, default method 개념 쉽게 설명

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

// 자바 8의 Collection 인터페이스에 추가된 removeIf 메서드
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;
    }
}
  • 주어진 boolean 함수(predicate; 프레디키트)가 true를 반환하는 모든 원소를 제거한다.
  • 범용적으로 잘 구현되었지만, 현존하는 모든 Collection 구현체와 잘 어우러지는 것은 아니므로 주의.(아래 예시 이해가 안됨.)
  • 자바 플랫폼 라이브러리에서 문제 예방
    • 구현한 인터페이스의 디폴트 메서드를 재정의하고, 다른 메서드에서는 디폴트 메서드를 호출하기 전에 필요한 작업을 수행하도록 했다

주의사항

  • 디폴트 메서드는 (컴파일에 성공하더라도) 기존 구현체에 런타임 오류를 일으킬 수 있다.
  • 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 한다.
  • 반면, 새로운 인터페이스를 만드는 경우라면 표준적인 메서드 구현을 제공하는 데 아주 유용한 수단이며, 그 인터페이스를 더 쉽게 구현해 활용할 수 있게끔 해준다.
  • 디폴트 메서드는 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아님을 명심해야 한다.

메서드 시그니처 : 메서드 이름과 파라미터

🍑 결론

  • 디폴트 메서드라는 도구가 생겼더라도 인터페이스를 설계할 때는 여전히 세심한 주의를 기울여야 한다.
  • 디폴트 메서드로 기존 인터페이스에 새로운 메서드를 추가하려면 기존 구현체들과 충돌하지는 않을지 반드시 고려해야 한다.
  • 새로운 인터페이스라면 릴리스 전에 반드시 테스트를 거쳐야 한다.
    • 수 많은 개발자가 각기 다른 방식으로 인터페이스를 구현할 것이니, 최소한 세 가지의 다른 방식으로는 구현해봐야 한다.
    • 또한 각 인터페이스의 인스턴스를 다양한 작업에 활용하는 클라이언트도 여러 개 만들어봐야 한다.
    • 인터페이스를 릴리스한 후라도 결함을 수정하는 게 가능한 경우도 있겠지만, 절대 그 가능성에 기대서는 안 된다.

Referenced by

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions