인터페이스에 기능이 추가되어 메서드를 새로 생성하면
인터페이스를 구현하는 모든 클래스에 컴파일 오류가 발생하면서
해당 메서드를 구현해야 하는 까마득한 현실이 펼쳐진다.
이 때 해당 메서드를 구현할 필요가 없는 클래스를 보며 잘못된 설계를 보기도 하고,
어영부영 코드를 구현해 컴파일 에러를 벗어나려고 했던 부끄러운 시도도 있었다.
최악에는 기능 추가를 접어두고 소극적인 자세로 돌아서기까지..
default Method를 처음 접했을 때,
이와 같은 엉망진창 행동들이 해결될 수 있겠다는 생각이 먼저 들었다.
하지만 그것이 진리가 아니었다.
default Method를 올바르게 이해해보자.
default Method는 자바에서 인터페이스를 제공하는 도중에
기능을 추가하면 호환이 되지 않는 문제를 해결하기 위해 등장했다.
interface Util {
void method();
void newMethod(); // ** 추가 **
}
// ** 컴파일 에러 발생, newMethod() 오버라이딩 필요 **
class Clazz implements Util {
@Override
public void method() {
// 코드
}
}
인터페이스에 기능이 추가되는 경우,
인터페이스를 사용하는 모든 구현 클래스에 컴파일 에러가 발생하기 때문에
각 클래스는 추가된 기능 메서드를 오버라이딩해야 한다.
구현 클래스가 수백개가 넘어가는 경우 기능 추가에 대한 부담이 커지게 되고
심각한 문제는 외부 라이브러리로 사용하는 사용자에게 오류가 발생하여 치명적이라는 것이다.
interface Util {
void method();
// ** default Method 선언 시, 인터페이스에서 직접 구현 **
default void newMethod() {
int value = 1; // ** 상태 코드는 부적절 **
}
}
인터페이스의 메서드에 default 키워드를 선언하면
해당 메서드는 인터페이스를 구현하는 클래스가 필수적으로 오버라이딩하지 않아도 된다.
default Method를 오버라이딩하지 않는 경우,
인터페이스에 구현된 메서드의 기본 로직을 사용할 수 있다.
interface Util1 {
int[] values = new int[3];
default void method() {
value[0] = 1; // ** 상태 변경 코드 부적절 **
}
}
interface Util2 {
default void method() { // ** 동일한 default Method 충돌 **
// 코드
}
}
위 상황 처럼 여러 인터페이스에서 동일한 시그니처의 default Method가 존재하는 경우
충돌이 발생하기 때문에 구현 클래스에서 default Method를 구현해서 사용하거나
default Method를 호출할 클래스를 명시해야 한다.
또한 default Method라고 하더라도 기본적으로 추상화가 목적인 인터페이스에서
구현의 일부만 제공하는 것이기 때문에 상태를 가지는 코드는 부적절하다.
default Method의 기능을 보면서 필요한 클래스에서만 해당 메서드를 오버라이딩하여
기능을 확장해야 겠다는 생각이 떠올랐다면 잘못된 신호이다.
default Method는 등장 배경에서 언급한 것처럼
기능 추가 시에 인터페이스를 사용하는 사용자의 호환 문제를 해결하기 위해 등장했다.
선택적으로 기능을 추가하기 위한 목적 등에 사용하는 것을 지양한다.
default Method는 기본적으로 하위 호환성을 목적으로만 사용이 권장된다.
default Method를 사용하면 시스템의 기능을 더욱 유연하게 확장할 수 있을 것 같다.
default Method의 목적이 하위 호환성이라는 것을 잊지 말고 올바르게 사용하자.