【问题标题】:Are Interfaces just "Syntactic Sugar"?接口只是“语法糖”吗?
【发布时间】:2011-03-09 06:01:56
【问题描述】:

我一直在玩 PHP 和 Python。

我一直在阅读 OO 编程中的接口,但看不出使用它的优势。

多个对象可以实现同一个接口,但是多重继承不提供这个?

为什么我需要创建一个“没有实现”的接口——主要是一个“契约”——如果我可以检查 Python 中的一个对象中是否存在一个方法,该方法继承自多个类?

接口是用其他语言创建的,因为它们不提供多重继承吗?还是我在这里遗漏了更重要的东西?

【问题讨论】:

标签: php python oop interface


【解决方案1】:

首先,最重要的是,尽量不要在 Python 和 Java 之间进行比较和对比。它们是不同语言,具有不同语义。比较和对比只会导致像这样的令人困惑的问题,您试图将 Python 不使用的东西与 Java 需要的东西进行比较。

这很像比较数字 7 和绿色。都是名词。除此之外,您将很难比较两者。

这是底线。

Python 不需要接口。

Java 需要它们。

多个对象可以实现同一个接口,但是多重继承不提供这个?

这两个概念几乎没有任何关系。

我可以定义大量共享一个公共接口的类。在 Python 中,由于“鸭子类型”,我不必仔细确定它们都有一个共同的超类。

接口是不相交的类层次结构的“意图”声明。它提供了一个不属于简单类层次结构的通用规范(可由编译器检查)。它允许多个类层次结构实现一些共同的特性,并就这些特性而言是多态的。

在 Python 中,您可以在没有接口的情况下使用多重继承。多重继承可以包括接口类,也可以不包括接口类。

Java 甚至没有多重继承。相反,它使用了一种完全不同的技术,称为“mixins”。

为什么我需要创建一个“没有实现”的接口——主要是一个“契约”——如果我可以检查 Python 中的一个对象中是否存在一个方法,该方法继承自多个类?

如果你在 Python 中创建一个接口,它可以是一种正式契约。声称所有子类绝对会按照接口声明的方式进行操作。

当然,麻木的人完全可以撒谎。他们可以从接口继承并错误实现所有内容。没有什么能阻止反社会者的不良行为。

您在 Java 中创建一个接口以允许多个对象类具有共同的行为。由于您在 Python 中很少告诉编译器,因此这个概念甚至不适用。

接口是用其他语言创建的,因为它们不提供多重继承吗?

由于概念不相关,因此很难回答。

在 Java 中,它们确实使用“mixin”而不是多重继承。 “接口”允许一些附加功能的混合。这是接口的一种用途。

接口的另一种用途是将“is”与“does”分开。类层次结构定义了对象是什么。接口层次结构定义了类的作用。

在大多数情况下,IS 和 DOES 是同构的,因此没有区别。

在某些情况下,对象是什么和对象做什么是不同的。

【讨论】:

    【解决方案2】:

    接口的实用性与静态类型的实用性直接相关。如果您使用 PHP 或 Python 等动态类型语言,接口确实不会显着增加语言的表现力。也就是说,任何可以被描述为使用接口的程序都可以在不使用接口的情况下无显着差异地表达。

    因此,Python 有一个相当模糊的“协议”概念(一种符合特定模式的实现,例如 iteration protocol),它基本上等同于同一件事,但没有编译时的其他好处检查它的值是有限的。

    另一方面,在静态类型语言中,接口对于允许实现与实现分离是必不可少的。在静态语言中,所有表达式的类型必须在编译时解析,因此通常必须在那时绑定到实现,从而限制了运行时的灵活性。接口定义如何在不定义特定实现的情况下访问功能,这允许静态语言在无需访问实现的情况下证明表达式是正确的。

    如果没有接口(或类似 C++ 的纯虚函数的等效公式),静态类型语言的表达能力将受到严重阻碍。实际上,存在许多实现(立即想到 Win32 和 COM),通过将函数指针存储在结构中(从而手动重新实现 C++ 的虚函数和 vtable 调用),在 C 中从本质上重现接口和虚拟调度的大部分功能.在这种情况下,表达能力有很大的不同,因为要表达相同的概念需要在程序中进行许多更改。

    接口只是类型多态的一个例子,而且是一个相当有限的例子。在支持parametric polymorphism(又名generics)的语言中,您可以完成更多工作。 (例如,如果没有泛型接口,C# 的 LINQ 是不可能的。)对于同类事物的更强大的形式,请查看 Haskell 的 typeclasses。

    【讨论】:

    • @Byron:我不是 PHP 专家,所以请赐教:您认为 PHP 中接口的 显着 值是什么(与鸭子打字相比Python 习语)?具体来说,如果没有它们,是否有任何操作不可能实现?
    • @Daniel Pryden 这似乎是一个非常人为的问题。没有理由证明没有它们就无法实现某些东西。我可以很容易地询问 C 中是否有任何操作无法使用 Assembly 以某种方式实现。奇怪的是,您如何在某些答案中贬低 PHP(和 PHP 程序员),但是您看不到所有 OOP 良好实践在动态和/或弱类型语言中都具有同等价值。仅仅因为可以在技术上调用不存在的方法并等待运行时错误并不意味着应该这样做。使用接口。
    • @Byron:我并不是要“贬低” PHP 或 PHP 程序员。如果你有这样的印象,我很抱歉。 PHP 和任何编程语言一样,是一种工具,所有工具都有优点和缺点。以其他方式争论简直是荒谬的。我想说的是,在动态类型语言like PHP 中,接口不添加significant 值。由于在动态语言中,所有错误无论如何都发生在运行时,无论是否使用接口,接口的增值小于 比像 Java 这样的语言。我们肯定可以同意吗?
    • 正如我在回答中试图解释的那样,在静态类型语言(尤其是具有早期绑定的静态类型语言,如 C++)中,接口(或类似纯虚方法的等效结构)是essential 能够解耦实现。如果不使用与接口等效的东西或至少同样复杂的东西,就不可能解耦实现。因此,对接口的句法支持使得 Java 比 C++ 更具表现力(尽管不支持多重继承使得 Java 比 C++ 更不具表现力)。
    • 感谢您编辑您的答案(删除了反对票)。 “表达性”是一个更合适的术语,而不是接口的实际价值和意图,无论该语言是否为编译语言,都应该是相同的。我个人无法想象在没有一些内置接口(如 Serializable、Iterator 和 RecursiveIterator)的情况下使用 PHP。
    【解决方案3】:

    即使在 Python 这样的鸭式语言中,界面也可以更清晰地表达您的意图。如果您有多个实现,并且它们共享一组方法,那么接口可能是记录这些方法的外部行为、为概念命名并使概念具体化的好方法。

    没有显式接口,您的系统中有一个重要的概念没有物理表示。这并不意味着您必须使用接口,但接口提供了具体性。

    【讨论】:

      【解决方案4】:

      在 PHP 和 Python 等动态类型语言中,接口的用途有限。您已经可以随时尝试调用任何对象上的方法,如果它不存在,您会收到运行时错误。

      在 Java 和 .NET 等静态类型语言中,接口变得很重要,因为在编译时会检查方法及其参数。

      现在,对于接口:

      Java 除了数组之外还有Lists。作为一般规则,数组用于基元(主要是数字类型),而Lists 用于对象。

      我可以有一个List<String>,它是一个字符串列表。我知道我可以给它add 字符串,然后从它返回get 字符串。

      我不知道它是哪个实现。它可以是ArrayList(由数组支持的列表)、LinkedList(由双向链表支持的列表)、CopyOnWriteArrayList(ArrayList 的线程安全版本)等......

      得益于多态性和接口,我不需要知道是哪种类型的List 对其进行List 操作。

      【讨论】:

        【解决方案5】:

        因为你想program against an interface而不是具体的实现(GoF 1995:18)

        【讨论】:

        • 嗯,我最近在大型顾问最佳实践书中听说你最近编写抽象类的代码。
        • @Woot4Moo:在大多数语言中,接口是所有方法都是抽象的类。不过,这在 .NET 中并不完全正确......
        • @Woot4Moo:视情况而定。抽象类更灵活,但可能会强制您使用deal with multiple inheritance。一如既往,为正确的工作使用正确的工具!
        • @ladenedge 我希望我的更多同事会考虑使用手套,而不是设计系统以在冬季骑自行车时保持人体温暖。
        【解决方案6】:

        因为有时您不想提供实现。

        Java Interface

        Java class

        【讨论】:

          【解决方案7】:

          是的。对于 PHP,接口只是克服缺乏多重继承的一种手段。对 IDE 有用的语义差异很小,由接口引起的冲突更少显然有助于新手程序员。但如前所述,在动态语言中并不是绝对必要的。 http://c2.com/cgi/wiki?MultipleInheritance

          【讨论】:

            【解决方案8】:

            请阅读Twisted Framework关于python中Zope接口功能的文章。

            【讨论】:

              【解决方案9】:

              它通常用于替换多重继承 (C#)。 我认为一些语言/程序员也将它们用作强制对象结构要求的一种方式。

              【讨论】:

                猜你喜欢
                • 2014-09-18
                • 1970-01-01
                • 2022-11-29
                • 1970-01-01
                • 2011-03-08
                • 2013-11-28
                • 2015-09-04
                • 2016-07-25
                • 2020-10-03
                相关资源
                最近更新 更多