如何理解介面-Java系列

lyning發表於2018-01-12

目錄結構

  • 前言
  • 什麼是介面?
  • 如何宣告介面?
  • 介面的作用?
  • 什麼時候可以考慮使用介面?
  • 什麼時候可以不考慮使用介面?
  • 線上介面文件化平臺
  • 總結

前言

今天有個同事問我,如何理解介面,剛好中午下班要去吃飯,邊走邊說,但是都沒有說到重點,所以想通過這篇文章來分享一下自己對介面的理解,閱讀需要2分鐘。

什麼是介面?

物件通過它們公開的方法來定義它們與外界的互動行為,而方法就形成了與外界互動的介面。例如電視機的開關按鈕就是你與塑料外殼另一側的電線之間的介面,你只要按下電源開關這個按鈕,就可以控制電視機開機和關機,而你不需要關注電視機開機和關機的細節,介面就是讓你知道它在做什麼,而無需知道它們怎麼做;介面更深層的理解是:使定義(規範和約束)和實現(具體的程式碼邏輯)分離,它是溝通(互動)的中介物(具體實現)的抽象化

如何宣告介面?

public inteface TV {

    // 開機
    public void open();
    
    // 關機
    public void close();
    
    // 選擇頻道
    public void selectChannel(Integer channel);
    
    // 設定聲音大小
    public void setVolume(Integer vlume);
    
    ...
}
複製程式碼

上面宣告瞭電視機的介面(程式語言層面的介面),暴露4個方法(與外界互動的介面),通過閱讀這些方法,你腦海裡大致可以對這個電視機建模,並且知道這個電視機可以做些什麼,這樣大家就都達成了一個共識,電視機都會具有哪些功能了;而具體要怎麼實現電視機的那些功能(開機、關機、選頻道、設定聲音大小)呢?這就交給不同的電視機廠商吧。

// 小米電視
public inteface MiTV extends TV {
    // 擴充套件玩遊戲介面
    public void playGame(String gameId);
}

public class MiTVImpl implements MiTV {

    @Overide
    pubilc void open() {
        // TODO 小米對開機的實現
    }
    
    @Overide
    public void close() {
        // TODO 小米對關機的實現
    }
    
    @Overide
    public void selectChannel(Integer channel) {
        // TODO 小米對選擇頻道的實現
    }
    
    @Overide
    public void setVolume() {
        // TODO 小米對聲音大小控制的實現
    }
    
    // 擴充套件玩遊戲介面
    @Overide
    public void playGame(String gameId) {
        // TODO 對遊戲的實現
    }
}
複製程式碼

從上面的程式碼中可以知道,小米電視機不僅實現了電視機的基本操作,自身還擴充套件了玩遊戲的介面,使用者只需要通過選擇小米電視提供的遊戲,就可以玩遊戲啦。

介面的作用?

  1. 介面即是設計:在設計層面,介面可以避免我們陷入對細節的過多思考,可以讓我們站在一個更高的視角對系統做更好的評估,比如系統的互動設計是否合理,功能是否缺失,是否具備可行性,是否過於複雜等等。
  2. 介面即是約定:在編碼層面,介面可以明確的告訴開發人員如何使用(介面的語義,需要什麼作為輸入,會有什麼輸出),而開發人員只需要根據這些約定去實現具體的功能程式碼即可。
  3. 統一類的共同行為:介面用來統一類的共通行為,當不同的類需要進行資訊共享時,是不需要特別去建立類間的關係。舉例來說,一個人(Human)及一隻鸚鵡(Parrot)都會吹口哨(whistle),然而 Human 及 Parrot 不應該為 Whistler 的子類,最好的做法是令他們為 Animal 的子類,而他們可以使用 Whistler 的介面進行溝通。
// 吹口哨
public inteface Whistler {
    /**
     * 吹口哨
     */
    public void whistle();
}

public class JuniorWhistler implements Whistler {
    public void whistle() {
        System.out.println("入門級口哨聲");
    }
}

public class SeniorWhistler implements Whistler {
    public void whistle() {
        System.out.println("高階口哨聲");
    }
}

// 定義動物介面
public inteface Animal {
    /**
     * 吹口哨
     *
     * @param whistle
     * @return
     */
    public void whistle(Whistler whistle);
}

public class Human implements Animal {
    
    public void whistle(Whistler whistle) {
        whistle.whistle();
    }
    ...
}

public class Parrot implements Animal {

    public void whistle(Whistler whistle) {
        whistle.whistle();
    }
    ...
}

public class Demo {
    public static void main(String[] args) {
        // 人吹口哨
        Human human = new Human();
        human.whistle(new JuniorWhistler());  // 入門級口哨聲
        
        // 鸚鵡口哨
        Human human = new Human();
        human.whistle(new SeniorWhistler()); // 高階口哨聲
    }
}
複製程式碼
  1. 使用時無需知道實現類:當介面有實現類時,在使用它的時候無需知道它的實現類是什麼(感興趣的可以瞭解一下多型依賴注入)。例如,一個事物因為口哨的噪音影響到其他人,對於其他人而言,就不需要知道噪音來源是來自人還是鸚鵡,因為他們可以確定,一個會吹口哨的事物正在吹口哨。舉一個更實際的例子,排序演算法可能會期待物件的型別是可以被比較的,於是它只需要知道物件的型別可以被以某種方式進行排序即可,這與物件的型別無關。whistler.whistle() 將會呼叫物件的實現方法 whistle,而不需要知道物件是以哪個類來實現 Whistler。
public inteface Whistler {
    public void whistle();
}

public class Human implements Animal {
    
    public void whistle(Whistler whistle) {
        whistle.whistle();
    }
    ...
}
複製程式碼

Human 類中的 whistle() 方法的實現 whistle.whistle() 不需要知道口哨具體的實現類是哪個,而 whistle(Whistler whistle)方法 只關注入參是 Whistler 型別就行。 至於 Java 如何實現動態繫結到具體的實現類上的方法,這個之後另開一篇文章來寫。

什麼時候可以考慮使用介面?

這雖然很難去定義(即使很多人一直使用面向介面程式設計),但個人還是根據自身的開發經驗淺談一下,如果說的不對,歡迎大家指教。

  1. 當專案沒有良好的開發規範、API文件還沒出、專案緊,當專案組有不少新人多時,需要使用介面,而這個介面的定義應該由有經驗、對業務和專案較為了解的人去定義,這樣子就可以嚴格約定好介面的輸入輸出、介面命名、引數命名,而不會被亂來,而新人只需要寫對應的實現就可以,這樣子在重構的時候,不會導致由於各種奇奇怪怪的問題而去改介面,一旦改了介面,出問題的可能性會更大(這個坑踩過,痛過,特別是沒有單元測試來做迴歸測試的時候)。
  2. 當需要使用到策略模式的時候,應該基於介面來實現,比如不同國家的貨幣換算等。
  3. 當框架功能對於系統基於介面設計的擴充套件非常友好時,應該使用介面,比如依賴注入,這個時候,介面可以使系統更具擴充套件性,更符合Open Close原則
  4. 基於SOA理念,暴露出來的服務必須是介面——阿里的Java開發規範手冊裡面就有嚴格說到這點。

什麼時候可以不考慮使用介面?

  1. 小專案,參與的人數較少時,時間緊,可以考慮不需要使用到介面,因為介面本身就不多,無需增加各種文件化的工作量。

線上介面文件化平臺

推薦的一些線上API管理平臺 Swagger Editoreolinker

  • swagger 偏向開發人員,需要掌握編寫swagger文件的一些語法,上手稍慢,但介面好看,功能也強大。
  • eolinker 全部都是圖形化,上手快,功能夠用。

總結

本文通過一些例子和個人的開發經驗,從介面的定義、介面的宣告、再到介面的適用場景,來與讀者分享本人對介面的理解,希望可以給讀者一些收穫,如果發現本人有理解不對的地方,或者有需要補充的地方,歡迎評論交流。

相關文章