You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
위의 코드에서 SingerSongwriter는 Singer 기능과 Songwriter 기능을 제공함을 손쉽게 알 수 잇다.
이렇게 선택적 기능을 혼합할 수 있다는 의미에서 믹스인이라고 불린다.
추상 클래스의 단점 (믹스인 구현 힘듦)
위와 같은 믹스인 구조를 클래스로 만들려면 가능한 조합 전부를 각각의 클래스로 정의해야 함
고도비만 계층구조 탄생
지원할 수 있는 선택적 속성이 N개라면 조합의 수는 2^n개나 됨
이와 같은 현상을 조합 폭발이라고 함
추상 클래스 방식에서는 두 부모를 섬길 수 없기에 믹스인은 인터페이스만의 장점
즉 클래스 구조와 달리 인터페이스로는 계층구조가 없는 타입 프레임워크를 만들 수 있다
인터페이스는 기능 향상에서 안전하고 강력한 수단
만약 래퍼 클래스와 같이 타입을 클래스로 정의한다고 하자
타입을 추상 클래스로 정의해두면 그 타입에 기능을 추가하는 방법은 상속 뿐
상속해서 만든 클래스는 래퍼 클래스보다 활용도가 떨어지고 깨지기는 더 쉽다.
인터페이스는 확장이 쉽고 제한이 적음
@jdk.internal.ValueBasedpublicfinalclassIntegerextendsNumberimplementsComparable<Integer>, Constable, ConstantDesc {
/** * A constant holding the minimum value an {@code int} can * have, -2<sup>31</sup>. */@NativepublicstaticfinalintMIN_VALUE = 0x80000000;
위는 Integer 클래스의 구현 정보
여러 기능을 구현하는 것에 상속보다 제약이 적은 것을 확인할 수 있음
인터페이스의 디폴트 메서드
인터페이스 메서드 중 구현 방법이 명백한 것이 있다면 디폴트 메서드로 제공할 수 있음
디폴트 메서드를 제공할 때는 상속하려는 사람을 위한 설명을 @implSpec 자바 독 태그를 붙여 문서화해야 한다
다음은 implSpec을 통해 디폴트 메서드를 설명하는 예시
/** * Receives notification when the state of a recording changes. * <p> * Callback is invoked when a recording reaches the {@code RUNNING}, * {@code STOPPED} and {@code CLOSED} state. * * @implNote The implementation of this method should return as soon as possible * to avoid blocking normal operation of Flight Recorder. * * * @implSpec The default implementation of this method is empty. * * @param recording the recording where the state change occurred, not * {@code null} * * @see FlightRecorder#addListener(FlightRecorderListener) * @see RecordingState * */defaultvoidrecordingStateChanged(Recordingrecording) {
}
인터페이스의 제약
인스턴스 필드를 가질 수 없음
public이 아닌 정적 멤버도 가질 수 없다(단, private 정적 메서드는 예외)
이는 추상 클래스에 비해 인터페이스가 가지지 못하는 제약점이라고 볼 수 있음
인터페이스에서 추상 클래스의 장점을 취할 수 있는 방법
인터페이스와 추상 골격 구현 클래스를 함께 제공하는 식으로 추상 클래스와 인터페이스의 장점을 함께 취할 수 있다.
인터페이스로는 타입을 정의하고, 필요하면 디폴트 메서드 몇개도 함께 제공한다.
그리고 골격 구현 클래스는 나머지 메서드들까지 구현한다.
이렇게 해두면 단순히 골격 구현을 확장하는 것만으로 이 인터페이스를 구현하는 데 필요한 일이 대부분 완료된다.
관례상 인터페이스 이름이 Interface라면 그 골격 구현 클래스의 이름은 AbstractInterface로 짓는다.
제대로 설계했다면 골격 구현은 그 인터페이스로 나름의 구현을 만들려는 프로그래머의 일을 상당히 덜어준다.
골격 구현과 그 예시 코드로 보는 장점
다음은 Map을 구현하는 골격 클래스 예시
publicabstractclassAbstractMap<K,V> implementsMap<K,V> {
/** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */protectedAbstractMap() {
}
// Query Operations /** * {@inheritDoc} * * @implSpec * This implementation returns {@code entrySet().size()}. */publicintsize() {
returnentrySet().size();
}