JAVA接口與抽象類
增加了間接性,提升了靈活性。
應用時需要權衡兩者的權重。通常應用於具體類變化可能性非常大的地方。
1 JAVA接口
接口就好比插座,構件就好比電器。只要新構件能與接口匹配,就能替換原有構件。
1.1 什麼是接口
JAVA接口是一些方法特徵的集合,源自系統中不斷出現的方法,是一種邏輯上的抽象。實現JAVA接口的兩個類往往完全不同,但卻擁有一組相同方法,提供類似服務。
JAVA接口將方法特徵與實現分割。JAVA接口就代表了一種角色,它包裝了該角色的屬性與操作,而實現類則扮演了這個角色的演員。
注:
JAVA中的方法特徵是指,僅包括方法名字、參量的數目和種類。這也是方法重載時的依據。
方法置換:則還包括返回類型、拋出異常是否相同。
1.2 爲什麼使用接口
接口是可插入性的保證。
Gardener不管理Fruit到底是什麼,只需調用相應接口即可完成與水果有關的工作。當前對象調用的具體類完全可以動態決定。
軟件系統的規模越大,生命週期越長,接口的重要性就越大。接口保證了軟件系統的靈活性、可擴展性和可插入性。
1.2.1 類型:
Java接口與抽象類用來聲明新的類型。
Java設計師應當使用Java接口與抽象類來將軟件單位與內部和外部耦合起來。
具體則表現爲,用Java接口和抽象類來進行變量、參量和返回類型聲明,以及數據類型轉換。
類型常以等級結構和組織的。
1.3 Java接口常見用法
1.3.1 單接口方法:
使Java能夠獲得C語言中函數指針所具有的能力,存儲和轉移調用某個函數。
例程:感覺上理解有點問題。下面的類結構。
publicinterface FuncPointer {
void run ();
}
class FunctorA implements FuncPointer {
publicvoid run () {
System.out.println (this.toString ());
}
}
class FunctorB implements FuncPointer {
publicvoid run () {
System.out.println (this.toString());
}
}
//test.java
publicclass Test {
publicstaticvoid main ( String [] args) {
FuncPointer[] pointers = new FuncPointer[2];
pointers[0] = new FunctorA ();
pointers[1] = new FunctorB ();
for(int i = 0; i < pointers.length; i++)
pointers[i].run ();
}
}
1.3.2 標識接口
只有接口名,沒有方法聲明,僅表示實現它的類屬於一個特定類型。
如Java中的Serializable與Remote
1.3.3 常量接口
用接口將常量封裝。這是錯誤的使用方法。Java中就存在這種錯誤用法:ObjectStreamConstants,ZipConstants,DndConstants
interface Constants {
staticfinalintDATE_LEN = 10;
staticfinalintFILE_NAME_LEN = 100;
staticfinal String PSWD = "admain";
}
1.4 接口應用實例
《日落紫禁城》中描寫奸臣嘴臉的詩:頭尖身細白如銀,上稱沒有頭毫分,眼睛長在屁股上,只認衣衫不認人。
“生、旦、淨、醜”,武松的行當便是武生,程雪娥的行當便是花旦。
2 抽象類
2.1 抽象類的定義
僅提供一個類型的部分實現(共享部分)。
不能創建實例,只能被繼承。
編程應當針對抽象編程。
2.2 抽象類的用途
抽象類是用來繼承的,具體類不應當用來繼承。在繼承關係形成的等級結構中,葉子節點應當是具體類,而內節點應當是抽象類(或Java接口)。
2.2.1 代碼重構方式:
2.2.2 抽象類應用規範
共享代碼,減少超類無用數據對內存的佔用。
2.3 Peter Coad繼承複用條件
繼承代表“一般化到特殊化的關係”,基類表一般,衍生類表特殊。
PeterCoad繼承條件:
l 子類是超類的一個特殊種類,而不是超類的一個角色。”Has-A”是聚合關係,”Is-A”纔是繼承關係。
l 永遠不需要將子類換成另一個類的子類的情況。如果不確定,就不應當設計成當前超類的子類。
l 子類具有擴展超類的責任,而不是置換或註銷超類的責任。如果子類要大量地置換超類行爲,則不應當便其成爲超類的子類。
l 只有在分類學角度有意義時,纔可以使用繼承。不要從工具類繼承,而應當是聚合關係。
Coad條件是里氏代換原則的衍生物。