peaches-book-study / effective-java

이펙티브 자바 3/E
0 stars 2 forks source link

Item 20. 추상 클래스보다는 인터페이스를 우선하라 #18

Open hyunsoo10 opened 6 months ago

hyunsoo10 commented 6 months ago

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

Item 20. 추상 클래스보다는 인터페이스를 우선하라

Assignee : hyunsoo10


🍑 서론

자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스가 있다. 인터페이스는 추상 클래스의 특수 형태로, 추상 클래스에서 멤버 변수와 메서드를 제거한 채 추상 메서드만을 남긴 형태이다.

추상 클래스는기본적으로 클래스이며, 이를 상속하고 확장하기 위해서 사용하는 것이고, 인터페이스는 구현한 객체들의 동일한 기능을 보장하기 위해 사용한다.

🍑 본론

1️⃣ 인터페이스는 기존 클래스를 확장하는데 유용하다.

기존 클래스에 새로운 인터페이스를 구현해서 다양한 기능들을 추가할 수 있다. Comparable, Iterable, AutoCloseable 인터페이스가 새로 추가됐을 때 표준 라이브러리의 수많은 기존 클래스가 해당 인터페이스들을 구현한채 릴리스 됐다.
반면에, 기존 클래스위에 새로운 추상 클래스를 끼워 넣는 작업은 쉽지 않다. 상속관계가 중간에 추가되면 하위에 있는 모든 자손 클래스들이 새로 추가된 추상 클래스를 상속하게 된다.
public class A extends C {
    ...

}

public class B extends A {
    ...

}

abstract class C {
    //난 추상 클래스야
}

//새로운 추상 클래스의 등장
abstract class D extends C{
    //난 새로운 추상 클래스야
}

// D -> C -> A -> B
public class A implements C {
    ...

}

public class B implements D {
    ...

}

interface C {
    //난 인터페이스야
}

//새로운 인터페이스의 등장
interface D{
    //난 새로운 인터페이스야
}

// C->A    D ->B 

2️⃣ 인터페이스는 믹스인 정의에 안성맞춤이다.

믹스인이란 클래스가 구현할 수 있는 타입으로, 믹스인을 구현한 클래스에 원래의 주된 타입외에도 특정 선택적 행위를 제공한다고 선언하는 효과를 준다.

📍대표적인 믹스인 예시

public interface Comparable<T> {
    /**
     * 
     * @param   o the object to be compared.
     * @return  a negative integer, zero, or a positive integer as this object
     *          is less than, equal to, or greater than the specified object.
     *
     * @throws NullPointerException if the specified object is null
     * @throws ClassCastException if the specified object's type prevents it
     *         from being compared to this object.
     */
    public int compareTo(T o);
}

자바의 Comparable은 자신을 구현한 클래스의 인스턴스들끼리는 순서를 정할 수 있다고 선언하는 믹스인 인터페이스이다.

3️⃣ 인터페이스로 계층구조가 없는 타입 프레임워크를 만들 수 있다.

현실에는 계층을 엄격히 구분하기 어려운 개념들이 있는데, 이는 인터페이스를 활용한다면 적절하게 사용할 수 있다. 작곡을 잘하는 가수들을 많이 찾아볼 수 있는데, 타입을 인터페이스로 정의하면, 가수 클래스가 Singer와 Songwriter 모두를 구현해도 문제되지 않는다. 심지어 Singer와 Songwriter 모두를 확장하고 새로운 메서드까지 추가한 제 3의 인터페이스도 정의할 수 있다.

public interface Singer  {
    AudioClip sing(Song s);
}

public interface Songwriter  {
    Song compose(int chartPosition);
}

//둘을 상속 받는 새로운 인터페이스도 작성 가능함
public interface SingerSongwriter extends Singer, Songwriter  {
    AudioClip strum();
    void actSensitive();
}

4️⃣ 래퍼클래스 관용구와 함께 사용하면 인터페이스는 기능을 향상시키는 강력한 수단이된다.

인터페이스의 메서드 중 구현 방법이 명백한 것이 있다면, 그 구현을 default 메서드로 제공해줄 수 있다. 단, default 메서드를 제공할 때는 @implSpec 자바독 태그를 붙여 문서화해야 한다.

interface D {
    String guessWhat();

    default String exact() {
        return "나는야 인터페이스의 구현 방법이 명백한 메서드야";
    }

}

📌 인터페이스와 추상 골격 구현 클래스를 함께 제공하는 식으로 인터페이스와 추상클래스의 장점을 모두 취하는 방법도 있다.

📌 인터페이스로는 타입을 정의하고 필요하다면 default 메서드 몇 개도 함께 제공한다. 그리고 골격 구현 클래스는 나머지 메서드들까지 구현하는 것이다.

📌 관례상 인터페이스 이름이 Interface라면 골격 구현 클래스의 이름은 AbstractInterface라고 짓는다. 대표적인 예시로 AbstractCollection, AbstractSet, AbstractList, AbstractMap 등이 핵심 컬렉션 인터페이스의 골격 구현이다.

📌 단, equals와 hashCode와 같은 Object의 메서드는 디폴트 메서드로 제공하면 안된다는 사실을 유념하자.


public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {

    //...

    protected AbstractList() {

    }

    //...

    public boolean add(E e) {
        add(size(), e);
        return true;
    }

    //...
    public abstract E get(int index);

    //...

    public int indexOf(Object o) {
        ListIterator<E> it = listIterator();
        if (o==null) {
            while (it.hasNext())
                if (it.next()==null)
                    return it.previousIndex();
        } else {
            while (it.hasNext())
                if (o.equals(it.next()))
                    return it.previousIndex();
        }
        return -1;
    }

    //...
}

🍑 결론

✏️ 일반적으로 다중 구현용 타입으로는 인터페이스가 가장 적합하다. 복잡한 인터페이스라면 구현하는 수고를 덜어주는 골격 구현 클래스를 제공하는 방법을 고려해보자.


Referenced by

pyeong114 commented 6 months ago

수정

수정 부탁드립니다^^

youngkimi commented 6 months ago

믹스 인의 유래를 아시나요?

이 이름은 메사추세츠 소머빌 지역의 스티브 아이스크림 가게에서 영감을 받았습니다. 아이스크림 가게의 주인은 기본적인 맛(바닐라, 초콜릿 등)과 추가적인 재료(땅콩, 쿠키, 사탕 등)의 조합으로 버무려진 아이스크림을 판매했는데. 이 아이스크림을 "믹스 인 (mix-in)"이라고 불렀다고 하네요 :)

유익하셨다면 좋아요 부탁드립니다 :)