【发布时间】:2008-09-23 20:48:36
【问题描述】:
我将选择 Java 作为示例,大多数人都知道,尽管其他所有 OO 语言都可以正常工作。
Java 与许多其他语言一样,具有接口继承和实现继承。例如。一个 Java 类可以从另一个类继承,并且在那里有实现的每个方法(假设父类不是抽象的)也被继承。这意味着接口是继承的,并且此方法的实现也是如此。我可以覆盖它,但我不必这样做。如果我不覆盖它,我已经继承了实现。
但是,我的类也可以“继承”(不是用 Java 术语)只是一个接口,而不需要实现。实际上接口在Java中确实是这样命名的,它们提供接口继承,但不继承任何实现,因为接口的所有方法都没有实现。
现在有这个article, saying it's better to inherit interfaces than implementations,你可能喜欢阅读它(至少是第一页的前半部分),它非常有趣。它避免了像fragile base class problem 这样的问题。到目前为止,这一切都很有意义,文章中所说的许多其他内容对我来说也很有意义。
让我感到困惑的是,实现继承意味着代码重用,这是面向对象语言最重要的属性之一。现在如果 Java 没有类(就像本文所希望的 Java 教父 James Gosling),它解决了实现继承的所有问题,但是你如何让代码重用成为可能呢?
例如如果我有一个类 Car 并且 Car 有一个方法 move(),它使 Car 移动。现在我可以为不同类型的汽车划分 Car 子类,它们都是汽车,但都是 Car 的专用版本。有些可能以不同的方式移动,这些无论如何都需要覆盖 move(),但大多数会简单地保留继承的移动,因为它们的移动方式与抽象父 Car 一样。现在假设Java中只有接口,只有接口可以相互继承,一个类可以实现接口,但是所有的类总是最终的,所以没有一个类可以从任何其他类继承。
当您有一个接口 Car 和数百个 Car 类时,您如何避免需要为每个类实现相同的 move() 方法? OO 世界中除了实现继承之外还有哪些代码复用概念?
有些语言有 Mixin。 Mixins 是我问题的答案吗?我读过它们,但我真的无法想象 Mixins 在 Java 世界中会如何工作,以及它们是否真的能解决这里的问题。
另一个想法是,有一个类只实现了 Car 接口,我们称它为 AbstractCar,并实现 move() 方法。现在其他汽车也实现了 Car 接口,它们在内部创建了一个 AbstractCar 的实例,并通过在其内部抽象 Car 上调用 move() 来实现自己的 move() 方法。但这不会白白浪费资源(一个方法只调用另一个方法——好吧,JIT 可以内联代码,但仍然如此)并且使用额外的内存来保存内部对象,你甚至不需要实现继承? (毕竟每个对象都需要更多的内存而不仅仅是封装数据的总和)对于程序员来说编写虚拟方法是不是很尴尬
public void move() {
abstractCarObject.move();
}
?
谁能想出一个更好的主意,即如何避免实现继承并仍然能够以简单的方式重用代码?
【问题讨论】:
-
我不喜欢称它为“接口继承”而是“接口实现”。这是我真正喜欢 Java 语言的一件事,两个不同的概念因此而得名。