在程序設計過程當中,讀者極可能遇到這樣一種困境:設計了一個接口,但實現這個接口的子類並不須要實現接口中的所有方法,也就是說,接口中的方法過多,對於某些子類是多餘的,咱們不得不浪費的寫上一個空的實現。java
今天小菜提到的「抽象接口」,就是用來解決這個問題的。設計模式
爲了避免誤導讀者,先說明一下,什麼是「抽象接口」。數組
所謂「抽象接口」,即在提供接口的同時,提供一個抽象類,用抽象類實現該接口(實際上這是缺省適配模式)。spa
下面小菜舉個例子,讓讀者體會這樣作的好處。設計
代碼寫的不咋地,爲了防止讀者看不懂,先上一張類圖:code
具體代碼:orm
ITestInterface.javablog
/* 假設有一個頂層接口 */ public interface ITestInterface{ void method1(); int method2(); boolean method3(); }
TestAbstract.java繼承
/* 抽象類abstract實現了ITestInterface頂層接口 */ public abstract class TestAbstract implements ITestInterface{ //找出接口中必要的方法,也就是子類必須實現的方法,定義成抽象方法,交由子類實現 public abstract void method1(); public abstract int method2(); //一些獨特的方法能夠在抽象類中默認實現 public boolean method3(){ return true; } }
TestClass1.java接口
/* 普通類TestClass1繼承了TestAbstract抽象類 */ public class TestClass1 extends TestAbstract{ //TestClass1必須實現抽象的method1方法,該方法最先是接口中定義的 public void method1(){ } //TestClass1必須實現抽象的method2方法,該方法最先是接口中定義的 public int method2(){ return 1; } //接口中的method3方法對於TestClass1可有可無,所以不作重寫。 }
TestClass2.java
/* 普通類TestClass2繼承了TestAbstract抽象類 */ public class TestClass2 extends TestAbstract{ //TestClass2必須實現抽象的method1方法,該方法最先是接口中定義的 public void method1(){ } //TestClass2必須實現抽象的method2方法,該方法最先是接口中定義的 public int method2(){ return 2; } //method3方法對於TestClass2來講相當重要,所以必須重寫。 public boolean method3(){ return false; } }
代碼精講:
從以上例子能夠看出,最高層的接口被一個抽象類實現,在抽象類中,咱們把關鍵的method一、method2方法定義成抽象方法,強制子類去實現,而「獨特」的method3方法在抽象類中作一個默認實現。
等到TestClass一、TestClass2繼承TestAbstract抽象類時,優點就體現出來了,TestClass一、TestClass2必須實現method一、method2,但若是用不到method3,能夠直接無視。
經過接口和抽象類的結合,避免了在實現接口的子類中出現大量的「無心義」實現,這個「無心義」實現,被緩衝到了抽象類中,完美展示了代碼複用(能夠把抽象類理解成接口和實現類之間的緩衝)。
須要指出的是,咱們既能夠選擇繼承抽象類,也能夠選擇實現接口,並非說必定要繼承抽象類,看狀況而定,這裏是兩種選擇,兩個機會。
寫到這,或許讀者以爲文章已經結束了,其實沒有。。。
這樣作的好處不單單是這一點,細細品味,假如咱們向接口中增長了一個方法。。。
具體代碼:
舒適提示:不要被代碼嚇到,其實這些代碼和上邊的差很少,只不過加了個方法而已。
ITestInterface.java
/* 假設有一個頂層接口 */ public interface ITestInterface{ void method1(); int method2(); boolean method3(); //接口中新增長了方法 String method4(); }
TestAbstract.java
/* 抽象類abstract實現了ITestInterface頂層接口 */ public abstract class TestAbstract implements ITestInterface{ //找出接口中必要的方法,也就是子類必須實現的方法,定義成抽象方法,交由子類實現 public abstract void method1(); public abstract int method2(); //一些獨特的方法能夠在抽象類中默認實現 public boolean method3(){ return true; } //抽象類中提供一個默認實現,這樣就能夠避免"驚動"全部子類 public String method4(){ return ""; } }
TestClass1.java
/* 普通類TestClass1繼承了TestAbstract抽象類 */ public class TestClass1 extends TestAbstract{ //TestClass1必須實現抽象的method1方法,該方法最先是接口中定義的 public void method1(){ } //TestClass1必須實現抽象的method2方法,該方法最先是接口中定義的 public int method2(){ return 1; } //接口中的method3方法對於TestClass1可有可無,所以不作重寫。 //新增的方法對於TestClass1來講相當重要,所以必須重寫 public String method4(){ return "Class1"; } }
TestClass2.java
/* 普通類TestClass2繼承了TestAbstract抽象類 */ public class TestClass2 extends TestAbstract{ //TestClass2必須實現抽象的method1方法,該方法最先是接口中定義的 public void method1(){ } //TestClass2必須實現抽象的method2方法,該方法最先是接口中定義的 public int method2(){ return 2; } //method3方法對於TestClass2來講相當重要,所以必須重寫。 public boolean method3(){ return false; } //新增的方法對於TestClass2來講可有可無,無需知道新增method4的存在 }
代碼精講:
這段代碼演示了假如項目已經成型,可是需求有變,咱們不得不向接口中增長一個新的方法,假如子類直接實現了接口,那麼這些子類都要修改,來實現接口新增的方法。
但本例中的TestClass一、TestClass2子類沒有直接實現接口,而是經過繼承抽象類間接實現接口,這樣好處一下就體現出來了!
向接口中新增的方法,能夠在實現接口的抽象類中緩衝一下,提供一個默認的實現,這樣一來,就沒必要強制全部的子類(經過繼承抽象類間接實現接口的類)都進行修改,能夠形象的理解爲「沒有驚動子類」。而須要使用這個方法的子類,直接重寫便可。
小菜感慨:
人類的智慧真偉大!數組和鏈表結合,產生了高效的哈希表;接口和抽象類結合,產生了優雅的缺省適配模式。你們努力吧!!!
寫在後面的話:
世間沒有完美的事物,設計模式也是如此,過多的討論優缺點沒有意義,合適的就是最好的,什麼是合適的呢?這纔是體現智慧的地方。