在程序设计过程当中,读者极可能遇到这样一种困境:设计了一个接口,但实现这个接口的子类并不须要实现接口中的所有方法,也就是说,接口中的方法过多,对于某些子类是多余的,咱们不得不浪费的写上一个空的实现。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子类没有直接实现接口,而是经过继承抽象类间接实现接口,这样好处一下就体现出来了!
向接口中新增的方法,能够在实现接口的抽象类中缓冲一下,提供一个默认的实现,这样一来,就没必要强制全部的子类(经过继承抽象类间接实现接口的类)都进行修改,能够形象的理解为“没有惊动子类”。而须要使用这个方法的子类,直接重写便可。
小菜感慨:
人类的智慧真伟大!数组和链表结合,产生了高效的哈希表;接口和抽象类结合,产生了优雅的缺省适配模式。你们努力吧!!!
写在后面的话:
世间没有完美的事物,设计模式也是如此,过多的讨论优缺点没有意义,合适的就是最好的,什么是合适的呢?这才是体现智慧的地方。