继承是一项强大的功能,非常适合构建基于类的层次结构,例如 JavaFX 中的层次结构。
但是为继承设计类是一件痛苦的事,并且充满了潜在的问题。这是一个常见的问题:如果您决定要使用 HashMap 来表示 Vehicles 的集合,该怎么办?问题在于,为子类编写 equals() 和 hashcode() 方法时,不会破坏 equals() 和 hashcode() 的约定,这比听起来更难。此外,继承破坏了封装,使您的子类依赖于超类中的实现细节,这会使您的代码变得脆弱或更难维护。
继承的替代方法是使用基于接口的类型系统,类似于 Java Collections API 使用的类型系统。
public interface Vehicle {
public void start();
:
}
public class Car implements Vehicle {
}
public class Bike implements Vehicle {
}
该接口用作基本类型,具有几个优点。最重要的是,任何实现 Vehicle 接口的类都可以传递给任何请求 Vehicle 的方法,无论该类是什么。尽管这看起来类似于继承,但实际上并没有基于类的层次结构。实现细节、封装和 equals() 合约的所有问题都消失了。
基于接口的类型系统的缺点有几个:
您必须能够使用接口定义稳健地指定基本类型的行为。没有这一点,作为基本类型的接口变得不方便。
接口必须由使用它的每个类完全实现(除非您为您的接口创建一个抽象的骨架实现类,例如 Collections API 中的 AbstractList)。
改变接口很困难……但编辑超类通常是有问题的。请记住,对超类的更改可能会在其子类中产生副作用,这些副作用取决于超类中的实现细节。
拥有基于接口的类型会使您的情况看起来像这样(使用静态工厂):
Vehicle car = Car.newInstance();
Vehicle bike = Bike.newInstance();
car.start();
bike.start();
TL;DR:基于接口的类型系统对于解决创建基于类的类型系统(继承破坏封装)的问题很有用,并且可以成为某些问题的良好替代解决方案。