Java 接口--面向對象的精髓

qeea6228 8年前發布 | 10K 次閱讀 面向對象編程 Java Java開發

接口有何用?面試寶典上背下來的總結,你真的明白嗎?

接口&工廠方法 其實很簡單>。

什么是接口

先看看生活中的接口,比如USB接口。

USB接口的設計者在最初就知道USB能支持這么多功能嗎?他們是怎樣未卜先知地設計的呢?其實他們也不知道以后USB上會連什么設備,他們只是定義了一個數據傳輸與供電的標準而已。

Java中也是類似的,定義了接口,就等于 定義了調用對象的標準。

接口的基本語法

  • 使用 interface定義;

  • 接口當中的方法都是抽象方法;

  • 接口當中的方法都是public權限(接口中的方法,寫不寫public修飾符,都是public權限,別的地方不行哦);

可以把接口理解成一個更加純粹的抽象類,因此它也不能生成對象。這要怎么辦呢?回想抽象類的處理方法,可以用一個類來繼承(接口中叫實現)它,從而在子類中生成對象。

一個最簡單的接口示例:

定義一個接口:

interface USB {
    public void read();    
    public void write();
}

定義它的子類,來實現這個接口:

class Phone implements USB {
    public void read() {
        System.out.println("Phone --> Read");
    }    
    public void write() {
        System.out.println("Phone --> Write");
    }
}

測試:

class Test {
    public static void main(String args []) {
        Phone phone = new Phone();
        //向上轉型
        USB usb = phone;
        usb.read();
        usb.write();
    }
}

運行結果:

繼續了解接口的語法:

  • 實現接口使用implements關鍵字;

  • 一個類可以實現多個接口;
    實現是特殊的繼承,換句話說,就是一個類可以繼承多個接口。
    修改上面的代碼:
    再定義一個WiFi接口:

interface WiFi {
    public void open();    
    public void close();
}

讓Phone也實現WiFi接口:

class Phone implements USB, WiFi {
    public void read() {
        System.out.println("Phone --> Reading");
    }    
    public void write() {
        System.out.println("Phone --> Writing");
    }
    //實現WiFi中的抽象方法
    public void open() {
        System.out.println("WiFi --> Open");
    }    
    public void close() {
        System.out.println("WiFi --> Close");
    }    
}

測試一下:

class Test {
    public static void main(String args []) {
        Phone phone = new Phone();
        //向上轉型時,就有兩種選擇
        USB usb = phone;
        usb.read();
        usb.write();

        WiFi wifi = phone;
        wifi.open();
        wifi.close();
    }
}

運行結果:

可以看到,用USB連接手機時,手機表現的就是USB的行為,用WiFi連接手機時,手機表現的就是WiFi的行為,這也是面向對象多態性非常明顯的體現。

  • 一個接口可以繼承多個接口

    注意這里不能寫成implements,因為我們只想繼承USB和WiFi接口的抽象方法,而不想實現它。

interface SbFi extends USB, WiFi {
  public void piu();
}

這樣SbFi接口就擁有read(),write(),open(),close()和piu()五個抽象方法了:)

接口的實踐

如果我們接到一個客戶的需求,用程序控制辦公室中的打印機,我們該怎么做呢?容易想到,先用一個類描述“打印機”,再用一些方法實現“開機”、“關機”、“打印”等動作,一個簡單的Printer類就能搞定了。

可是如果客戶提出了新的需求,辦公室又買了一臺其他品牌的打印機,讓你修改之前的代碼。這時要怎么做呢?都是打印機,只是品牌不同,功能略有差異,容易想到用接口或者繼承。接口更靈活一些,所以我們寫出了下面的代碼:

首先定義一個Printer接口,描述打印機都有的行為:

interface Printer {
    void open();
    void print(String s);
    void close();
}

在惠普打印機類中,實現Printer中的抽象方法:

class HPPrinter implements Printer {
    public void open() {
        System.out.println("HP: open");
    }
    public void print(String s) {
        System.out.println("HP: print--> " + s);
    }
    public void close() {
        System.out.println("HP: close");
    }
}

在佳能打印機中,又增加了新的方法,清洗:

public class CanonPrinter implements Printer {
    public void open() {
        System.out.println("Canon: open");
    }
    public void print(String s) {
        System.out.println("Canon: print-->" + s);
    }
    public void close() {
        this.clean();
        System.out.println("Canon: close");
    }

    public void clean() {
        System.out.println("Canon: clean");
    }

}

測試:

注意,這里使用對象的向上轉型,能減少重復代碼。不然就得用HPPrinter和CanonPrinter生成的對象分別調用open, print, close方法,很麻煩。如果以后有100臺打印機,豈不是得寫300行?

class Test {
    public static void main(String args []) {
        Printer printer = null;
        //為簡便,flag模擬用戶選擇使用哪臺打印機
        int flag = 1;
        if(flag == 0) {
            //向上轉型
            printer = new HPPrinter();
        } else if(flag == 1) {
            printer = new CanonPrinter();
        }

        printer.open();
        printer.print("向上轉型好用吧~");
        printer.close();
    }
}

運行:

大功告成。但是這樣就足夠了嗎?

如果我們的打印機代碼,是在一個辦公自動化的系統當中。可能有各種各樣的功能,要使用打印機。那每次使用時,都要把Test類中的這一段寫一遍嗎?如果以后有100個地方要用,豈不是要把這一段寫100次?更可怕的是,如果又添加了新的打印機,豈不是要修改這100段代碼?太容易出錯了。所以,我們和重復代碼,是勢不兩立的(振臂一呼)!

進擊的工廠方法模式減少重復代碼的一般方法就是,把重復的代碼放在一個地方(封裝起來),等要用的時候,就調用它,而不是再寫一遍。仔細看Test類,重復的地方,不包括最后三行,主要是根據用戶的選擇,生成打印機對象,并向上轉型為Printer類型的部分。

我們可以設計一個類,在里面添加一個函數,它的功能就是根據用戶的選擇生成打印機對象,以后我們直接調用這個函數就行了。函數的參數,就是用戶的選擇,返回值,就是一個Printer類型的對象。

class PrinterFactory {
    //添加static是為了調用方便
    public static Printer getPrinter(int flag) {
        Printer printer = null;
        if(flag == 0) {
            printer = new HPPrinter();
        } else if(flag == 1) {
            printer = new CanonPrinter();
        }        
        return printer;
    }    
}
class Test {
    public static void main(String args []) {
        int flag = 1;
        Printer printer = PrinterFactory.getPrinter(flag);
        printer.open();
        printer.print("對象的轉型好用吧~");
        printer.close();
    }
}

這樣,就算要增加100臺打印機,也只用在PrinterFactory中添加 else if(flag == xxx) 的代碼,不用修改Test類。

這就是著名的簡單靜態工廠方法模式。

PrinterFactory并不關心Printer類有多少個子類,這樣我們就能夠自由地修改Printer子類了。

工廠方法模式的思路很簡單,就是把生成對象的代碼,封裝在工廠類當中。

 

 

來自:http://geek.csdn.net/news/detail/108448

 

 本文由用戶 qeea6228 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!