编程范式(五)--- 接口和抽象类

45 阅读3分钟

接口和抽象类

语法特性

抽象类的特性

  • 抽象类不允许被实例化,只能被继承。也就是说,不能new一个抽象类的对象出来,会报编译错误
  • 抽象类可以包含属性和方法。方法既可以包含代码实现,也可以不包含代码实现。不包含代码实现的方法叫作抽象方法
  • 子类继承抽象类,必须实现抽象类中的所有抽象方法

接口特性

除开java8新特性,接口的特性有:

  • 接口不能包含属性(也就是成员变量)
  • 接口只能声明方法,方法不能包含代码实现
  • 类实现接口的时候,必须实现接口中声明的所有方法

从语法特性上对比,这两者有比较大的区别,比如抽象类中可以定义属性、方法的实现,而接口中不能定义属性,方法也不能包含代码实现等等。除了语法特性,从设计的角度,两者也有比较大的区别。

抽象类实际上就是类,只不过是一种特殊的类,这种类不能被实例化为对象,只能被子类继承。继承关系是一种is-a的关系,相对于抽象类的is-a关系来说,接口表示一种has-a关系,表示具有某些功能。对于接口,有一个更加形象的叫法,那就是协议(contract)。

两者存在的意义

抽象类

继承能解决代码复用的问题。所以,抽象类也是为代码复用而生的。多个子类可以继承抽象类中定义的属性和方法,避免在子类中,重复编写相同的代码。

代码复用本身就是继承的作用,非抽象类也可以做为父类复用。但是这种思路虽然达到了代码复用的目的,但是无法使用多态特性了。虽然可以使用空实现的方法让子类覆写,但是不够优雅,也有风险

  • 定义空方法,会影响代码的可读性。如果不熟悉父类的设计,那么一个空实现就是一种迷惑,阅读时不查看子类的覆写逻辑,就弄不明白空方法的用途
  • 在创建子类时,可能也会忘记覆写父类中的空实现,而且如果不熟悉父类的设计思想,可能都无法理解空方法的用途
  • 非抽象父类可以被实例化,实例化后调用空方法,增加了被误调用的风险

接口

抽象类更多的是为了代码复用,而接口就更侧重于解耦。接口是对行为的一种抽象,相当于一组协议或者契约。调用者只需要关心抽象的接口,不需要了解接口的实现。接口实现了约定和实现相分离,可以降低代码间的耦合性,提高代码的可扩展性。接口是一些设计原则得以实现的基石。

如何选择二者

  • 如果要表示一种is-a的关系,并且是为了解决代码复用的问题,就用抽象类;如果要表示一种has-a关系,并且是为了解决抽象而非代码复用的问题,那就可以使用接口。
  • 从类的继承层次上来看,抽象类是一种自下而上的设计思路,先有子类的代码重复,然后再抽象成上层的父类(也就是抽象类)。而接口正好相反,它是一种自上而下的设计思路。在编程的时候,一般都是先设计接口,再去考虑具体的实现。

总结

接口和抽象类的区别,从定义,特性,存在的意义,应用上做区分,就会有一个清晰的思路了解两者的不同和用法。