【问题标题】:Why make Abstract classes and Interfaces?为什么要制作抽象类和接口?
【发布时间】:2011-01-23 03:55:01
【问题描述】:

好吧,我本来想问有什么区别,但之前已经回答过了。但现在我要问他们为什么会产生这些差异? (这里说的是java,不知道其他语言是不是也一样)

这两件事看起来非常相似。抽象类可以定义方法体,而接口不能,但是可以继承多个接口。那么,为什么他们(“他们”我指的是 Sun 在他们编写 Java 时)不做一件事,您可以编写一个方法体并且这种类型可以被一个类多次继承。

无法编写方法主体或扩展我看不到的多次是否有一些优势?

【问题讨论】:

    标签: java interface abstract-class multiple-inheritance


    【解决方案1】:

    多重继承在一种语言(实际上是编译器)中更难实现,因为它可能导致某些问题。这些问题之前已经在这里讨论过:What is the exact problem with multiple inheritance

    我一直认为这是 Java 中的一种妥协。接口允许一个类实现多个契约,而不用担心多重继承。

    【讨论】:

      【解决方案2】:

      您描述的另一种方法是 C++ 使用的方法(例如 mixins)。与这种“多重继承”相关的问题相当复杂,并且在 C++ 中受到了一些批评。

      【讨论】:

      • C++ 没有我理解的 mixins。 Mixin 可以在运行时添加到类中(“将 Logger 行为添加到此 DBI 实例”),这不是 C++ 语言的核心部分。
      • @Philip 我不明白你的意思。 Mixin 经常在 C++ 中使用,也许在 Grady Booch 的书中最为人所知。
      • 我认为我们只是不同意“mixin”的定义。没什么大不了的,继续前进。
      • @Philip 我搜索了“运行时混合”,现在我明白了你的意思。动态语言很时髦,在这方面我似乎落后了。
      • 老实说,我对 mixins 的体验仅限于 Perl 的 Moose::Roles,它们也不完全相同。如今,我们拥有的概念比我们所能描述的要多。
      【解决方案3】:

      因为允许类为同一个方法签名继承多个实现会导致一个明显的问题,应该在运行时使用哪一个。

      Java 通过仅支持接口的多重继承来避免这种情况。每个接口中声明的签名可以更容易组合(Java基本上使用所有方法的联合)

      【讨论】:

      • 啊,我知道我一定缺少了什么,这是有道理的!
      【解决方案4】:

      C++ 中的多重继承会导致语义模糊,例如 diamond inheritance problem。 MI 非常强大,但具有复杂的后果。

      将接口作为一种特殊情况还可以提高概念的可见性,作为信息隐藏和降低程序复杂性的一种手段。在 C++ 中,定义纯抽象基是成熟程序员的标志。在 Java 中,您会在程序员发展的更早阶段遇到它们。

      【讨论】:

        【解决方案5】:

        让它们成为一件事是 Scala 家伙采用 Traits 的路线,这是一个可以有方法并支持多重继承的接口。

        我认为接口对我来说是干净的,因为它们只指定需求(按合同设计),而抽象类定义常见的行为(实现),所以不同的工具用于不同的工作?接口可能也允许在编译期间更有效地生成代码?

        【讨论】:

          【解决方案6】:

          继承意味着你继承了父类的性质(意义)和责任(行为),而接口实现意味着你履行了一个契约(例如Serializable),它可能与类的核心性质或职责无关。

          抽象类让你定义一个你想要通用而不是直接实例化的性质,因为它必须是专门的。你知道如何执行一些高级任务(例如根据一些参数做出决定),但你不知道一些低级操作的细节(例如计算一些中间参数),因为它取决于实现选择。解决此问题的另一种方法是Strategy design pattern。它更灵活,允许运行时策略切换和 Null 行为,但它更复杂(并且运行时切换并不总是必要的)。此外,您可能会丢失一些含义和类型工具(多态性和类型检查变得有点困难,因为策略是一个组件,而不是对象本身)。

          抽象 class= is-a,策略 = has-a

          编辑: 至于多重继承,请参阅 Pontus Gagge 的回答。

          【讨论】:

            【解决方案7】:

            考虑这个例子:

            public abstract class Engine
            {
              public abstract void switchPowerOn();
              public abstract void sprinkleSomeFuel();
              public abstract void ignite();
            
              public final void start()
              {
                switchPowerOn();
                sprinkleSomeFuel();
                ignite();
              }
            }
            

            抽象类可以帮助您拥有可以或不能被覆盖的可靠基础方法,但在这些方法中,它使用抽象方法为您提供执行特定操作的机会。在我的示例中,不同的发动机在如何打开电源、为点火洒一些燃料以及进行点火方面有不同的实现,但是发动机的启动顺序始终保持相同。

            这种模式被称为“表单模板方法”,坦率地说,对我来说,这是 Java 中抽象类的唯一合理用法。

            【讨论】:

              猜你喜欢
              • 2018-07-19
              • 1970-01-01
              • 2020-07-06
              • 1970-01-01
              • 1970-01-01
              • 2010-11-13
              • 2013-02-17
              相关资源
              最近更新 更多