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