【发布时间】:2017-03-10 20:20:14
【问题描述】:
我无法理解何时/为什么要实现继承以及何时/为什么要通过接口实现继承。请耐心等待我解释..
假设我们有一个父类 Animal,我们希望用 3 个子类扩展它:Dog、Cat 和 Mouse。
假设所有动物都能够eat()、sleep()、scratch() 和move()。并且Dog 能够pant()。有了这些知识,我们将继续将前 4 个行为添加到 Animal 超类,并让 Dog、Cat 和 Mouse 扩展 Animal。我们还将方法 pant() 添加到 Dog 类,因为只有狗 pant()。
现在,如果我们希望添加另一个名为 waggleTail() 的方法,但只有 Cat 和 Dog 表现出这种行为,会发生什么情况。我们不能将此行为添加到Animal,因为Mouse 也将继承该行为(并且鼠标不会摆动它的尾巴)。另一种方法是将方法waggleTail() 添加到Dog 和Cat 类,但不添加到Mouse 类。然而,这种方法没有意义,因为我们会通过两次编写方法waggleTail() 来违反 DRY 原则(不要重复自己)。我们希望每个方法编写一次,而且只写一次。
也许我们可以通过创建一个继承自Animal 的新子类TailWagglingAnimal 来解决这个问题,将方法waggleTail() 添加到这个子类中,然后让Dog 和Cat 都继承自这个新的子类。这听起来很合理,直到您意识到还有许多其他此类异常,并且我们必须对每个异常重复此过程(这会将继承层次结构扩展至无止境)。
此外,如果我们有一种特定类型的Dog(我们称他为“Coton de Tulear”),它表现出Dog 的所有其他行为(例如气喘吁吁),但它不会摇摆不定它的尾巴。如果我们让“Coton de Tulear”直接从Animal 继承,它将无法 pant()。如果我们让它继承自Dog,它将能够摆动它的尾巴(bec Dog extends TailWagglingAnimal)。如果我们让Dog 直接扩展Animal,然后创建一个名为TailWagglingDog 的新子类(与TailWagglingAnimal 相同),那么Cat 将无法继承此行为(因此我们需要在其中的某处复制该行为违反 DRY 原则的 Cat 层次结构)。
我们要做什么?
基于 stackoverflow 上的数十个线程(以及几本 OO 设计书籍),建议从 Dog 类中删除方法 waggleTail() 并将其添加到接口中。让我们调用接口TailWaggler,然后让所有的狗(“Coton de Tulear”除外)实现这个接口。但是,我很难理解这为什么/如何有用。
如果你仔细想想,这意味着所有 50 多只狗面包(假设有 50 只狗面包需要表现出这种行为)都需要添加工具 TailWaggler 关键字,因为只有一种 @ 987654368@ 没有表现出这种行为。这不仅意味着程序员需要进行大量额外的手动工作(在每个类的开头添加实现 TailWaggler)这意味着所有后代都需要关注他们表现出的行为(如果我们将此行为添加到父类并扩展父类,情况就不会如此)。如果我们只有几个这样的案例,这可能很好,但如果我们有几十个或数百个这样的案例呢?最后,当我们添加新类型的狗子类时,最终将有一种Dog 是另一种不会表现出 Dog 父类行为之一的类型 - 所以这意味着我们需要缓慢但肯定地删除几乎(父)Dog 类的所有行为并将它们添加到接口?然后我们需要确保所有的子类都实现了几十个不同的接口。有人可能会建议我们将所有相关行为组合在一个界面中,但这只有在不同狗表现出的行为一致时才有可能 - 如果不是这种情况怎么办?)
谢谢!
【问题讨论】:
-
忍受我。熊。 Bare 意味着赤身裸体。
-
使用Mixins 是解决这个问题的一种方法——允许组合和代码重用。但是,Java 没有对 Mixins 的原生支持,您需要使用委托或静态实用程序来解决这个问题。
-
如果您提供一个来自您处理的“复杂/抽象”案例的实际示例可能会更好。在我看来,您的 Animal、Dog、Cat 示例可能无法按原样描述您的情况。有了具体的例子,我们或许可以共同得出一个解决方案。
-
@MickMnemonic java 8 默认接口实现是一种 Mixins 形式。
-
@minus 是的,默认方法允许使用 mixins;但是当您阅读一些内容时,您会发现 java 背后的人确实建议以这种方式看待它们。
标签: java oop inheritance