JDK8漫談——加強接口

解決什麼問題

  • 向下兼容。添加方法,全部的實現類必須實現此方法,不然會編譯報錯。這意味着每一次的接口升級都會傷筋動骨。可是這是一把雙刃劍必定要把握好場景,不要濫用。
  • 類爆炸。使用時,須要輔助類。即要記憶接口可能還須要記憶輔助類。
  • 內置行爲。使用時,須要關注外部的過程性的處理邏輯。好比:循環,排序,過濾,轉換類型,取默認值等。

背後思想

  • 封裝。經過封裝的思惟,把細節封裝成方法。經過服務的調用解決代碼複用和關注點過高的問題。
  • 兼容性。不少軟件一升級就得從新學一遍~~

內容介紹

組成部分

接口一直不斷在加強,可是整體來講,仍是隻放抽象的內容,不放實例化相關的內容。java

  • 公有常量。
  • 公有方法。沒有具體實現,通常不須要寫public,默認的就是。
  • 私有方法(JDK9)
  • 靜態方法。有具體實現,和靜態方法調用一直。
  • 默認方法。有具體實現,能夠被實現類重寫而且直接調用。
public interface Powerable {
    /**
     * 公有常量
     */
    String NAME = "me";

    /**
     * 公有方法
     */
    void print();

    /**
     * 靜態方法
     * @param name
     */
    static void cry(String name){
        System.out.print(name+"is crying");
    }

    /**
     * 默認方法
     */
    default void fly(){
        System.out.print(Powerable.NAME+"can fly");
    }

}

注意事項工具

  • 不容許有成員變量。

方法優先級

  • 類優先於接口。若是一個子類繼承父類和接口有相同的方法實現。那麼子類繼承父類方法
  • 子類中的方法優先於父類中方法
  • 若是以上條件都不知足,則必須顯示覆蓋/實現其方法,或者聲明成abstract

實戰

最佳實踐

減小類爆炸

常常使用到的抽象邏輯封裝成默認方法,減小輔助類類。.net

@Test
public void test_default(){
    Map<String,String> map = new HashMap();
    String defaultIntro = "";

    //方案一,須要使用工具類
    String utilsIntro = MapUtils.getorDefault(map, "intro", defaultIntro);
    System.out.println(utilsIntro);

    //方案二,無需使用工具類
    System.out.print(map.getOrDefault("intro", defaultIntro));
}
  • 減小須要思考多份職責,須要關注接口還須要關注類。
  • 減小類,提供代碼優雅度。

內置處理

細節封裝成默認方法,減小關注度和出錯率,提高服務的穩定和優雅性code

public void test_default_encapsulation() {
    Map<String, String> map = new HashMap<>();
    //方案一:經過顯式的循環,感知的細節太多。須要顯示感知類型,還須要關注Entry對象以及getKey和getValue
    for (Map.Entry entry : map.entrySet()) {
        System.out.println(entry.getKey() + "," + entry.getValue());
    }
    //方案二:經過顯式的循環,感知的細節太多。須要顯示感知類型,還須要key以及map獲取
    for (String key : map.keySet()) {
        System.out.println(key + "," + map.get(key));
    }
    //方案三:內置方法,不用考慮循環,不須要考取取值細節
    map.forEach((key, value) -> {
        System.out.println(key + "," + value);
    });
}
  • 封裝細節,把細節變成方法。
  • 改變思惟方式,從面向細節到面向服務。原來是:循環map,經過什麼類型獲取key,value,執行任務,任務裏使用key,value;如今是:map循環執行任務,任務裏使用key,value。

最佳反例

放具體的實例

好比把原來的工廠放到如今的接口默認方法裏。對象

default Powerable run(int type) {
    switch (type) {
        case 1:
            return new Person();
        default:
            return null;
    }

}
  • 接口不穩定,會不斷變修改。
  • 接口依賴實現,本末倒置。

使用default來完成多態

子類重寫父類的default方法blog

  • 關注點過高,接口職責不清晰。須要看一下接口有哪裏default,而後還須要判斷哪些是須要重寫的,哪些只能能用邏輯。

再次思考

  • 接口是否變成萬能類,職責愈來愈多,愈來愈重?
  • 何時使用抽象類,何時使用接口?
  • 何時使用工具類,何時使用接口的靜態方法?
  • 如何減小重複思考,如何界定邊界?

參考資料

相關文章
相關標籤/搜索