2020/07/24

[筆記] Effective Java #20 介面優於抽象類

Effective Java 3rd 簡體中文版筆記 #20 介面優於抽象類
早期介面 (interface) 與抽象類 (abstract class) 最不同的在於介面沒有預設方法,但 Java 8 後介面可以有預設方法。如果要實現 abstract class 必須使用繼承 (extends),Java 是單一繼承,不過在實作 (implements) 介面上沒有數量限制。當 class 要實作介面是比繼承 abstract class 容易的,範例如下,String 要實作 Comparable 與 Serializable,如果都是介面,只需要使用 implements,但如果是繼承,就會出現 type hierarchy 的狀況。
// interface
public final class String 
    implements Serializable, Comparable<String>, CharSequence {
    ...
}
// 錯誤用法,abstract class
public abstract class Comparable<T> {
    ...
}
public abstract class Serializable extends Comparable {
    ...
}
public final String extends Serializable {
    ...
}
介面是定義 mixin (混合類型) 的理想選擇,Comparable 表示允許物件之間作比較,Serializable 則表示序列化的細節,String 同時實作兩者,表示它是屬於兩種的混合類型。介面間也可以使用繼承,像是歌手與作曲家,分別定義為兩個介面 (Singer 與 Songwriter),有些歌手本身也是作曲家,就實作兩個介面,也可以新增第三個介面的實作,然後在其中增加適合的方法。
public interface Singer {
    AudioClip sing(Song s);
}

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

public interface SingerSongwriter extends Singer, Songwriter {
    AudioClip strum();
    void actSensitive();
}
利用介面與 abstract class 的優點,提供骨架實現 (skeletal implementation) 的 class。實際應用像是 collections 中的 AbstractSet 及 AbstractList,當要實作客製化的 List 時,繼承 AbstractList 就能省去不少功夫,skeletal implementation 也能結合 wrapper class pattern,如果客製化 List 已經有繼承其它類,基於單一繼承原則,無法繼承 AbstractList,這時可以實作 List 介面,然後利用 helper class (private inner class) 繼承 AbstractList,最後在客製化 List 的實作方法中調用該 helper class。
public interface List<E> {
    boolean add(E e);
    boolean remove(Object o);
}

public abstract class AbstractList<E> implements List<E> { 
    @Override
    public boolean add(E e) {
        // implementation
    }
}

public class CustomizedList extends OtherClass implements List<E> {
    private AbstractListDelegator delegator = ...;
    private class AbstractListDelegator extends AbstractList {
        @Override
        public boolean remove(Object o) {
            ...
        }
    }
    @Override
    public boolean add(E e) {
        return delegator.add(E e)
    }
    @Override
    public boolean remove(Object o) {
        return delegator.remove(o);
    }
}
詳細範例
https://dzone.com/articles/favour-skeletal-interface-in-java
http://web.mit.edu/6.005/www/fa14/classes/14-inheritance/#interfaces_and_abstract_classes

轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2020/07/effective-java-20-interface-abstract.html