【问题标题】:Java interface and abstract class issueJava接口和抽象类问题
【发布时间】:2010-05-15 14:07:02
【问题描述】:

我正在看书——Hadoop: The Definitive Guide

在第 2 章(第 25 页)中,提到“新 API 支持抽象类而不是接口,因为这些更容易发展。例如,您可以将方法(具有默认实现)添加到抽象类,而无需打破类的旧实现”。这是什么意思(尤其是“打破类的旧实现”的意思)?是否有人可以向我展示一个示例,为什么从这个角度来看抽象类比接口更好?

提前致谢, 乔治

【问题讨论】:

    标签: java design-patterns class interface


    【解决方案1】:

    在接口的情况下,接口中定义的所有方法必须由实现它的类实现。

    给定接口A

    interface A {
        public void foo();
    }
    

    还有一个 B 类:

    class B implements A {
    }
    

    必须为接口中定义的方法提供一个实现:

    class B implements A {
        @Override
        public void foo() {
            System.out.println("foo");
        }
    }
    

    否则是编译时错误。现在采用一个抽象类带有方法的默认实现

    abstract class C {
        public void bar() {
            System.out.println("bar");
        }
    }
    

    从这个抽象类继承的类可能如下所示:

    class D extends C { }
    

    没有错误。但如果它倾向于这样做,它也可以覆盖默认方法实现。

    作者在那里说的是:如果您的 API 还不稳定并且您需要适配接口(是的,抽象类也是接口(在 OOP 中)),那么抽象类允许您添加东西而无需打破已经存在的课程。然而,这只适用于非抽象方法。如果添加抽象方法,那么它们仍然需要在每个派生类中实现。但是,如果您的 API 仍在不断发展并且已经有很多东西在其上构建,那么它可以让您的生活更轻松。

    【讨论】:

    • 谢谢!我感到困惑的是书中的这句话——“打破类的旧实现”。 “类”是指类派生自抽象类,还是抽象类所基于的类?
    • @George:表示从旧版本的接口/抽象类派生的类。对于接口,它不再有效,因为它无法实现您添加到接口的方法。使用抽象类和非抽象方法,它可以愉快地使用基类的实现,甚至不知道它的存在。
    • 谢谢!您的意思是假设在版本 1 中,抽象类具有方法 Foo,并且从抽象类派生的类实现了 Foo。并且在抽象类的版本2中,增加了一个新的方法Goo,派生类仍然可以工作而不受影响(如果Goo在抽象类中有默认实现)?
    • @George:没错。然而,如果你有一个接口(或者将 Goo 抽象化),你将不得不遍历 每个 派生类并添加一个合适的方法实现。
    • 我可能会补充一点,一些铁杆 OOP 人群可能会指出存在许多技术和模式来避免这种事情。虽然这可能是真的,但 Hadoop 的作者可能有充分的理由不使用它们。例如,设计模式通常以实现复杂性换取灵活性。我很高兴从事一个一切都是插件并且所有东西都尽可能灵活的项目。使用起来很痛苦,因为即使是简单的事情也需要一段时间才能构建。我承认模式有一定的地位,但它们也可能被过度使用。
    【解决方案2】:

    如果您将具有默认实现的方法添加到抽象类,则任何派生类都无需更改任何内容。

    或者,如果您向接口添加方法,则任何实现该接口的类都需要实现该方法 - 否则它们将无法编译。

    【讨论】:

    • 该死的。我应该把这些例子排除在外。我又花了四分钟 ;-)
    • @George,贾斯汀:我做了一个改变,希望让那部分更清楚,因为“基类”在那儿是错误的术语(imo;或者我可能在那里理解错了)
    • @George - 我的意思是,如果添加了新方法(具有默认实现),则从抽象类派生的类不需要更改。
    • @Johannes - 谢谢! FWIW,我认为我的回答可能太简短了。 +1 给你,因为你更详细地充实了它:)
    • 再想一想,我可能只是提供了一个示例,说明接口/基类被扩展的情况以及为什么会导致问题......嗯,还在学习如何编写:)
    【解决方案3】:

    另请参阅 Eclipse Wiki 中的以下指南

    不断发展的基于 Java 的 API

    Adding an API method

    示例 4 - 添加 API 方法

    向类或接口添加 API 方法会破坏与现有客户端的兼容性吗?

    如果将方法添加到客户端可以实现的接口中,那么这绝对是一个突破性的变化。

    如果将方法添加到不允许客户端子类化(实现)的类(接口)中,则它不是重大更改。

    但是,如果该方法被添加到客户端可以子类化的类中,则该更改通常应被视为重大更改。之所以得出这个严厉的结论,是因为客户端的子类可能已经拥有自己的同名方法实现。将 API 方法添加到超类会削弱客户端的代码,因为如果客户端的现有方法满足新添加方法的 API 约定,那将是纯粹的巧合。在实践中,如果这种名称重合的可能性足够低,这种变化通常被视为非破坏性的。

    【讨论】:

      猜你喜欢
      • 2012-03-25
      • 1970-01-01
      • 1970-01-01
      • 2012-07-14
      • 1970-01-01
      • 2011-12-05
      • 2011-07-02
      • 2015-06-27
      • 1970-01-01
      相关资源
      最近更新 更多