说明:
关于本博客使用的书籍,源代码Gitee仓库 和 其他的相关问题,请查看本专栏置顶文章:《Effective Java》第0条:写在前面,用一年时间来深度解读《Effective Java》这本书
正文:
通过题目和日常的编程我们也能感觉到,如果要扩展一个类,最好的方式是定义一个接口,抽象类的确很少用。
那么首先来对比一下,抽象类和接口的优缺点:
1、由于Java只允许单继承,所以抽象类作为类型定义就受到了一定的限制,而实现接口则没有限制,可以实现多个接口。
2、任何类都可以实现一个接口,因为接口都是public的,所以这个类无论是在什么层次结构中,都可以实现。但是抽象类受到修饰符的限制。
3、原文P79:现有的类可以很容易被更新,以实现新的接口。如果这些方法尚不存在,你所需要做的就只是增加必要的方法,然后在类的声明中增加一个implements子句。但对于抽象类来说,无法更新现有的类来扩展新的抽象类(单继承)。如果你希望两个类扩展同一个抽象类,就必须把抽象类放到类型层次的高处,这样它就成了那两个类的一个祖先。遗憾的是,这样做会间接地伤害到类层次,迫使这个公共祖先的所有后代类都扩展这个新的抽象类,无论它对于这些后代类是否合适。举例说明:
假设我们有一个基础抽象类 Animal(动物),它有两个子类 Bird(鸟类)和 Mammal(哺乳类)。现在需要让 Bird 和 Mammal 都支持 “飞行” 相关的行为(比如 fly() 方法,蝙蝠就是哺乳类会飞的),于是我们可能会想到:在 Animal 和 Bird/Mammal 之间加一个抽象类 FlyingAnimal(会飞的动物),让 Bird 和 Mammal 都继承它,这样就能共享飞行相关的抽象方法了。
此时类层次变成:
Animal → FlyingAnimal → Bird
Animal → FlyingAnimal → Mammal
但问题来了:Mammal 中还有很多子类(比如 Dog、Cat),它们其实并不会飞,但因为 Mammal 继承了 FlyingAnimal,这些不会飞的哺乳动物也被迫 “继承” 了飞行相关的抽象方法(必须实现 fly())。这显然不合理 —— 狗和猫并不需要飞行能力,但类层次的设计迫使它们卷入了不相关的行为。
4、原文P79:接口是定义 mixin(混合类型)的理想选择。不严格地讲,mixin 类型是指:类除了实现它的“基本类型”之外,还可以实现这个 mixin 类型,以表明它提供了某些可供选择的行为。例如,Comparable是一个mixin接口,它允许类表明它的实例可以与其他的可相互比较的对象进行排序。这样的接口之所以被称为mixin,是因为它允许任选的功能可被混合到类型的主要功能中。抽象类不能被用于定义mixin,同样也是因为它们不能被更新到现有的类中:类不可能有一个以上的父类,类层次结构中也没有适当的地方来插入mixin。
5、原文P80:接口允许构造非层次结构的类型框架。类型层次对于组织某些事物是非常合适的,但是其他事物并不能被整齐地组织成一个严格的层次结构。
比如书上的歌唱家和作曲家的例子,通过接口就非常容易去实现一个人既是歌唱家又是作曲家,只需要实现歌唱家和作曲家的接口即可,但是如果通过抽象类来实现就非常的麻烦,原因还是因为单继承导致。即使是使用组合方式,也不是一件容易的事情,原文P80:如果在整个类型系统中有n个属性,那么就必须支持 2^n 种可能的组合。这种现象被称为“组合爆炸”。类层次臃肿会导致类也臃肿,这些类包含许多方法,并且这些方法只是在参数的类型上有所不同而已,因为类层次中没有任何类型体现了公共的行为特征。
举例说明:比如还是用歌唱家和作曲家举例,这时候我们再添加一个指挥家,这里有三种类型。那么在组合的时候就会出现8种类型,分别是:
歌唱家,作曲家,指挥家,歌唱作曲家,歌唱指挥家,作曲指挥家,歌唱作曲指挥家,还有一个什么家都不是的人。
这就是“组合爆炸”,并且这些类中没有一个类能体现公共的行为
6、原文P80:接口使得安全地增强类的功能成为可能。如果使

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



