
6.5 接口的应用
在第4.3.4节,我们介绍了父对象与子对象之间的类型转换,实际上,这种转换规则对于接口也是适用的。我们先看一段代码,如代码6.13所示。

程序的输出结果为:

从上面的代码来看,我们可以把任何实现了Animal接口的类的对象都转型为Animal接口类型,这是合法的,且不需要强制类型转换。转型为Animal接口类型后,只要调用的方法是该接口中声明的方法,一切就都可以正常运行。在代码的倒数第3行,我们把Bird对象转换为FlyableAnimal接口类型,由于animals[2]是Animal接口类型,因此需要强制类型转换,然后就可以调用FiyableAnimal接口所定义的fly方法了。
使用接口可以让我们摆脱对特定类的依赖。我们看代码6.14。


我们需要为动物园中的这些动物请一些驯兽师,比如专门为狗请一个驯兽师,同时也为猫和鸟各请一个驯兽师,那么代码就会像上面一样,驯兽师(Trainer)依赖于特定的动物。如果动物园又来了一个新成员(比如大象),那么我们还要再请一个驯兽师,于是继续扩充代码,直到有一天我们不再有耐心为每个动物都写一个Trainer类。
这是一种多么愚蠢而且拙劣的设计!
下面我们来看看如何轻松地完成这个任务,仅仅需要一个Trainer就可以了,如代码6.15所示。

无论新来的动物是什么,它至少是个动物(Animal接口类型),因此,我们可以用一个Animal类型的变量来引用任何动物对象,在驯兽师(Trainer)的训练方法(train)中,让动物叫两声、走两步。
这样一来,我们设计的Trainer类就摆脱了对特定类型的依赖,于是在Zoo类中也就不需要为每个动物都去创建对应的Trainer了。我们看代码6.16。

看,这些代码如此的简洁,而这些都得益于接口。
上面介绍的例子是接口的一种应用方式。在此,并不是要求读者一定要如此设计代码,只是告诉读者,如果这么使用接口,则会使事情变得更加美好。