기존 클래스에 새로운 인터페이스를 구현하려면, 간단하게 해당 인터페이스를 클래스 선언문에 implements 구문으로 추가하고 인터페이스가 제공하는 메소드들을 구현하기만 하면 끝이다. 반면에 기존 클래스에 새로운 추상 클래스를 상속하기에는 어려움이 따른다.
두 클래스가 같은 추상 클래스를 상속하길 원한다면 계층적으로 두 클래스는 공통인 조상을 가지게 된다. 만약 두 클래스가 어떠한 연관도 없는 클래스라면 클래스 계층에 혼란을 줄 수 있다.
- 믹스인이란 어떤 클래스의 주 기능에 추가적인 기능을 혼합한다 하여서 믹스인이라고 한다. 그러므로 믹스인 인터페이스는 어떤 클래스의 주 기능이외에 믹스인 인터페이스의 기능을 추가적으로 제공하게 해주는 효과를 준다.
- 추상 클래스가 믹스인 정의에 맞지않은 이유는 기존 클래스에 덧씌울 수 없기 때문이다. 자바는 단일 상속을 지원하기 때문에 한 클래스가 두 부모를 가질 수 없고 부모와 자식이라는 클래스 계층에서 믹스인이 들어갈 합리적인 위치가 없다.
- 믹스인 인터페이스엔 대표적으로 Comparable, Cloneable, Serializable 이 존재한다.
public class Mixin implements Comparable {
@Override
public int compareTo(Object o) {
return 0;
}
}- 추상 클래스로 만들었기 때문에 Singer 클래스와 SongWriter 클래스를 둘다 상속할 수 없어 SingerSongWriter라는 또 다른 추상 클래스를 만들어서 클래스 계층을 표현할 수 밖에 없다.
- 만약 이런 Singer 와 SongWriter와 같은 속성들이 많이 있다면, 그러한 클래스 계층구조를 만들기 위해 많은 조합이 필요하고 결국엔 고도비만 계층구조가 만들어질 것이다. 이러한 현상을 조합 폭발이라고 한다.
public class People implements Singer, SongWriter {
@Override
public void sing(String s) {
}
@Override
public void compose(int chartPosition) {
}
}public abstract class Singer {
abstract void sing(String s);
}
public abstract class SongWriter {
abstract void compose(int chartPosition);
}
public abstract class SingerSongWriter {
abstract void compose(int chartPosition);
abstract void sing(String s);
}
//
public class People extends SingerSongWriter {
@Override
public void sing(String s) {
}
@Override
public void compose(int chartPosition) {
}
}- 타입을 추상 클래스로 정의해두면 해당 타입에 기능을 추가하는 방법은 상속 뿐이다.
- 상속해서 만든 클래스는 래퍼 클래스보다 활용도가 떨어지고 쉽게 깨진다.
- 인터페이스의 메서드 중 구현 방법이 명백한 것이 있다면, 그 구현을 디폴트 메서드로 제공해줄 수 있다. 이는 프로그래머의 일을 상당히 덜어준다.
- 디폴트 메서드를 제공할 때는 상속하려는 사람을 위한 설명을 @implSpec 자바독 태그를 붙여 문서화해야 한다.
https://dzone.com/articles/favour-skeletal-interface-in-java