抽象的极致是「接口」
文章来源:《Head First Java》修炼感悟。
上一篇文章中,老白学习了原始对象 Object 的一些基础知识,类一旦创建就会具有两重以上的身份:自身类型和 Object 类型。 本篇文章,老白继续研究「多态」的重磅武器「接口」。 请注意,此接口并非 GUI 中的接口,也不是 IO 接口,更不是管道接口,这个接口是为了解决 Java 的多重继承问题的接口。
如何设计 Animal 的某些行为
前几个章节中设计的 Animal 类很完美,每个子类都能很好地继承父类。 假如某一天,客户突发奇想,想要为 Dog 增加互动行为 beFriendly()
,因为他很喜欢 Dog。 你会怎样做? 最简单的做法就是在 Dog 中加入 beFriendly()
方法:
public class Dog extends Canine {
public void beFriendly() {
// TODO:
}
}
可是这样真的好吗? 如果客户又提出 Cat 也要实现这个行为又该怎么办呢? 那就在 Cat 中也添加这个方法:
public class Cat extends Feline {
public void beFriendly() {
// TODO:
}
}
很快你就会意识到,这并不是一个好的方案,而且无法实现「多态」引用。 把这个方法放到父类 Animal 中会更好,于是:
abstract class Animal {
abstract void beFriendly();
}
你认为这样就可以了吗? 想象一下,Lion 或者 Tiger 表现出 beFriend()
行为会是一个多么怪异的场景。 所以,这个方案也不适合。
如果 Java 能够多继承就好了,可惜 Java 只支持单继承。 幸运的是 Java 提供了「接口」功能,如果实现了「接口」就可以达到类似多继承的效果。
什么是接口
你可以认为接口就是抽象类,一个抽象到极致的类。 接口中的每一个方法都是抽象的,所以子类必须实现接口中的每一个方法。
定义接口
接口的定义与类定义差不多,只是把 class
关键字改为 interface
,另外接口内的所有方法都声明为 abstract
,下面来看看如何定义:
public interface Pet {
public abstract void play();
public abstract void beFriendly();
// TODO:
}
其实,定义接口中的方法不必使用关键字 public
和 abstract
,就像这样:
public interface Pet {
void play();
void beFriendly();
// TODO:
}
但要记住,接口中的每一个方法都是抽象的,也就是说没有方法体,所以直接使用分号 ;
结束。
实现接口
如果要实现某个接口,可以在类名后面使用 implements
+ 接口名称,表示该类要实现这个接口。 比如 Dog 的类定义:
public class Dog extends Canine implements Pet {
public void roam() {
// TODO: 覆盖 Canine 的方法
}
public void play() {
// TODO: 实现接口 Pet 的抽象方法
}
public void beFriendly() {
// TODO: 实现接口 Pet 的抽象方法
}
}
可以看到,因为 Dog 实现了 Pet 接口,所以必须实现 Pet 接口中定义的抽象方法。 如果 Dog 的父类 Canine,或者顶层父类 Animal 中还有抽象方法没实现,Dog 也必须要实现父类中的抽象方法。 就像这样:
结束语
接口的出现,为设计类结构提供了更多思路。 一个设计良好的类结构应该是健壮的、能够适应大部分情况的。 下一篇文章,老白打算仔细聊一聊接口的应用,重温一次接口的威力,敬请关注!
《 上一篇 对象的起源 Object | 下一篇 接口的约定,言出必行 》 |
---|