1. 程式人生 > >【Java入門提高篇】Day2 介面

【Java入門提高篇】Day2 介面

  上一篇講完了抽象類,這一篇主要講解比抽象類更加抽象的內容——介面。

  什麼是介面呢?先來看一個現實中的栗子,我們常用的插座,一般分為兩孔和三孔,所以基本上不管是什麼電器,只要插頭插進去就可以正常使用,想想看,如果沒有這樣的規範,有十幾種不同的插座孔,每個電器的插頭都不一樣,還不得崩潰掉。

  先來看個栗子:

/**
 * @author Frank
 * @create 2017/11/22
 * @description 可比較介面,用於實現類物件排序
 */
public interface Isortable {
    //a>b則返回正整數,相等則返回0,否則返回負整數
int compareWith(Object a); }

  這是一個簡單的介面,使用interface關鍵字來定義介面。

  介面是描述可屬於任何類或者結構的一組行為,是用於定義程式的一種規範,任何實現了介面的類都必須實現介面的所有方法,體現的是“如果你是。。。就必須能。。。”的思想。

  在介面中,不能有方法的實現,也就是說,裡面所有方法都是public abstract的,裡面只能由靜態變數,不能存在普通成員變數,可謂是抽象的集大成者。那為什麼要使用介面呢?

  還是繼續我們之前的比喻,任何按照規範進行生產的插頭都能獲得電力,而不同插座雖然生產工藝不同,質量也不一樣,但並不影響電器的正常使用,電器並不會關心插座的內部實現,這樣就能遮蔽掉一些底層的細節,只暴露出介面供電器使用。

  對於軟體開發而言,按照介面的規範進行呼叫,就能獲得期望的功能,按照介面的規範實現介面的方法,就能提供所期望的功能。介面的意義在於抽象,而抽象可以很好的解耦合。

  我們來回頭看看上一篇的栗子,我們從具體的商品類中抽象出了一個商品類,從而實現了程式碼複用和統一管理,也降低了程式的耦合度,比如一個排序方法,引數設定為Phone類的話,那就只能往裡面放Phone型別的物件,而如果設定成Goods類,則Phone、Television、Computer類的物件都可以傳入進去,這樣就降低了程式的耦合度,也就是相互之間的依賴度。

  而介面則是更高層的抽象,主要是對於行為的抽象,可以把它看作是一組規範或者要求,就好比要開車就要先考駕照,這個駕照就相當於介面,你有了這個駕照,就代表你有開車的能力和資格,因為“如果你要有駕照,你就必須能開車“。這樣交警就不會為難你了,你跟交警之間通過駕照這個介面進行交流和溝通,而不是用口才去說服他。想一想,如果沒有駕照這種規範,總不能沒見到一個開車的人都要先當場測試一下他的能力才能讓他上路吧。

  在複雜的系統構架中,往往分成很多層級,上層要使用下層提供的服務,而層級之間是通過介面進行交流的,上層對於下層僅僅是介面的依賴,而不是具體類的依賴,因為只要實現了相應的介面,就可以提供相應的服務,就像只要有教師資格證,就代表你有當老師的資格和本事,關注的不是你這個物件,而是你教書的能力,也就是你能提供的服務。當下層需要改變的時候,只要介面不變,上層可以完全不用改變,甚至可以在上層不知情的情況下完全換掉下層程式碼,正因為介面的存在,讓層級之間的耦合度大大降低。就像你的U盤,如果舊的壞了,直接換上新的U盤就可以插上,即插即用,電腦跟U盤之間通過介面進行交流。

  好了,說了這麼多,真是很羅嗦,還是來看程式碼吧,實踐出真知。我們來把上一篇的內容稍做修改,上面的程式碼定義了一個Isortable介面,用於比較兩個物件,以用於之後的排序。

  然後我們定義一個Sort類,用於進行排序,可以使用各種型別的排序,如氣泡排序,選擇排序,快速排序,希爾排序,這裡簡單起見,只用了氣泡排序。

/**
 * @author Frank
 * @create 2017/11/22
 * @description 排序類
 */
public class Sort {
    //氣泡排序,從大到小排序
    public static void bubbleSort(Isortable[] isortables){
        for (int i = 0;i<isortables.length-1;i++){
            for(int j = 0;j<isortables.length-i-1;j++){
                if(isortables[j].compareWith(isortables[j+1])<0){
                    //交換兩者的值
                    Isortable tmp = isortables[j+1];
                    isortables[j+1] = isortables[j];
                    isortables[j] = tmp;
                }
            }
        }
    }
}

  然後在Goods類中實現Isortable介面。使用implements關鍵字。

/**
 * @author Frank
 * @create 2017/11/21
 * @description
 */
public abstract class Goods implements Isortable{
    //定義各個類共有的屬性
    private String title;
    private Double price;

    //定義構造器
    public Goods(String title, Double price) {
        this.title = title;
        this.price = price;
    }

    //定義設定器和訪問器
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    //宣告抽象列印方法
    abstract void print();

    //實現Isortable介面,覆蓋compareWith方法
    @Override
    public int compareWith(Object a) {
        //由於還沒有說明泛型,所以直接強制轉換型別了
        Goods g = (Goods)a;
        if(this.price > g.getPrice()){
            return 1;
        }else if(this.price < g.getPrice()){
            return -1;
        }
        return 0;
    }

}

  由於Goods類實現了Isortable介面,所以繼承於Goods類的所有類也都實現了該介面,接下來我們修改一下測試類進行測試。

/**
 * @author Frank
 * @create 2017/11/21
 * @description
 */
public class Test {
    public static void main(String[] args) {
        Goods[] goodsList = new Goods[3];
        goodsList[0] = new Phone("IphoneX",9688.00,5.8,24.0);
        goodsList[1] = new Computer("Alienware15C-R2738",17699.00,"i7-7700HQ","GTX1060");
        goodsList[2] = new Television("SAMSUNG UA78KU6900JXXZ",21999.00,78.0,"4K");

        Sort.bubbleSort(goodsList);
        for (Goods g:goodsList)
            System.out.println(g.getTitle()+" "+g.getPrice());
    }
}

  輸出如下:

SAMSUNG UA78KU6900JXXZ 21999.0
Alienware15C-R2738 17699.0
IphoneX 9688.0

  這樣就按價格進行了從大到小的排序了,怎麼樣,介面用起來很簡單方便吧,這樣以後Goods類不管有多少子類,都可以用Sort的bubbleSort方法進行排序,還可以修改或者增加Sort類的方法,讓它按你想要的規則進行排序。

  其實在Java中已經有類似的介面了,Comparable介面和Comparator介面,因為使用了泛型,就不會像這裡的程式碼需要強制型別轉換了(而且強制型別轉換也有一定風險),而很多方法可以對實現了Comparable介面的類進行排序,這就很棒了。(手動滑稽)

  在實際使用中,往往每個人都會負責不同的模組開發,不同的模組之間通常用介面進行交流,因為如果A程式設計師開發A1類,需要使用B程式設計師開發的B1類,若是直接呼叫B1類,那就只能先等B1類開發好之後才能進行A1類的開發,而且如果B1類有任何改動,很可能需要修改A1類的程式碼,這樣耦合度就很高了,而如果使用介面的話,A1類只需要接受介面型別的引數,就可以直接呼叫相應的方法,而B1類只需要實現介面即可,B1類即使有改動,只要介面不變,那麼它向A1類提供的服務也不會變,這樣A1類就不需要進行改變,耦合度就降低了。

  現在小結一下:

  介面是對一組特定行為的抽象,是一種規範,只能有方法簽名,而不能有實現,所有的方法預設為abstract,且訪問許可權只能是public,不能有普通成員變數,可以有靜態成員變數,介面可以繼承介面,一個類可以實現一個介面,也可以實現多個介面,介面的存在可以降低程式的耦合度,增加程式的靈活性。引用大神的話便是,介面和實現分離,面向介面程式設計。

  至此,介面講解完畢,歡迎大家繼續關注。