【问题标题】:In Java, is there a performance gain in using interfaces for complex models?在 Java 中,将接口用于复杂模型是否会提高性能?
【发布时间】:2010-04-15 04:45:17
【问题描述】:

标题很难理解,但我不知道如何用另一种方式来概括。欢迎任何编辑澄清。

我被告知并建议使用接口来提高性能,即使在不特别需要常规“接口”角色的情况下也是如此。在这种情况下,对象是大模型(在 MVC 意义上),具有许多方法和字段。

向我推荐的“好用处”是创建一个具有独特实现的接口。肯定不会有任何其他类实现这个接口。有人告诉我这样做更好,因为它向将使用此类方法的其他类“暴露更少”(或接近的东西),因为这些对象从其接口引用对象(所有公共方法来自接口中重现的实现)。

这对我来说似乎很奇怪,因为这对我来说似乎是 C++ 的用途(带有头文件)。我明白了这一点,但是在 Java 中呢?

为这种独特的实现制作接口真的有意义吗?我非常感谢您对该主题进行一些澄清,因此我可以证明遵循这种行为以及复制所有声明所带来的麻烦。


编辑:感谢大家的回答,这真的很有帮助和启发性(其中大多数,不仅仅是“接受”的人)。

显然在性能上没有优势,而且我现在可以从中获得更大的兴趣范围(取决于情况),除了接口的通常 OO 角色。

【问题讨论】:

  • 不确定使用接口的主要原因是否是性能。
  • @Martinho - 我知道使用接口的主要原因。但是这个“建议”让我困扰了一段时间。

标签: java performance interface


【解决方案1】:

使用接口与性能没有太大关系(可能除了开发团队的性能,即开发速度)。它更多的是控制依赖关系,并分离程序的不相关部分。

如果您在代码中直接依赖具体的 C 类,则该代码更难进行单元测试等。如果您改为依赖接口,则可以在单元测试中创建模拟实现。

当然,您可能不需要将类的所有方法拉到父接口中。事实上,您可能不需要一个父界面。分析该类的使用情况(尤其是像您这样的大类),您可能会发现两个甚至更多不同的方法组,由不同的客户端使用(例如,一组客户端只查询对象状态,而另一组客户端更新它)。这使得创建两个或多个不同的接口成为可能,每个接口都更简单、更干净。

这种分析甚至可能得出这样的结论,即您的班级正在尝试做太多事情(而不是拥有single responsibility),您最好将其中的一些内容提取到一个单独的班级中!换句话说,一旦您开始考虑接口并对其进行编程,您就会开始看到不同层次的设计,这可能会带来更好的设计解决方案。

综上所述,如果经过以上所有分析,您仍然没有看到模型类的接口没有使用,请记下它。比方说,半年后重新审视它。然后,如果您仍然觉得它没有收回成本,那就扔掉它。接口 - 就像您程序的任何其他元素一样 - 应该始终有一个明确的目的和存在的理由(并且比“我的同事告诉我创建它”更好)。它们不是灵丹妙药。如果你巧妙地使用它们,你可以让你的代码变得更好。如果你愚蠢地使用它们,你会让你的代码变得更糟。你在这里发布这个问题意味着你想学习如何巧妙地使用它们,这很好:-)

【讨论】:

  • 我确实没有考虑过测试,在这种情况下它可能很有用。这不是给我的原因,但对于我拥有的其中一些对象来说,这确实是一个有效的观点。
  • 最多的点赞、最多的细节、良好的格式以及一般的建议,谢谢。 打勾
【解决方案2】:

首先,接口没有任何性能优势。如果有的话,使用多态代码和动态调度(如 C++ 虚函数)是有代价的。

不要把接口看作是增加表达能力的东西,而是限制你写得更好的东西。恕我直言,接口很重要,原因有以下三个:

1) 他们可以帮助你编写更好的封装、数据隐藏、稳定性等方面的代码。

2) 他们可以通过考虑你试图表示什么而不是如何实现它来帮助你区分行为和实现。无法添加状态可以防止您意外添加状态。

3) 它们允许您在未来扩展事物并将您的代码分成独立的单元。每个组件只知道它需要知道的关于其他服务的信息。

您可以使用没有状态的抽象类来完成其中的一些操作,但接口是专门为此而设计的,并且具有多个子类型的好处。在 C++ 中,此类抽象类通常用于模拟接口。

现在,如果您可以直接使用类编写一个具有完美封装级别的庞大系统,那就太好了。但是对于类,通常很容易过早引入状态并创建连接。

你应该总是写接口吗?当然不是。永远害怕“永远”的规则 :) 它总是在浪费的工作和=无用的复杂性和好处之间取得平衡。随着时间和经验的积累,你会得到它的直觉。

另外,头文件本质上是接口文件。它们通常定义允许的行为,但没有定义状态。如果您先学习 C,然后再学习 Java(有些学校会这样做),您会了解 C 中的 ADT,然后了解 Java 中使用接口的 ADT。

【讨论】:

  • 我确实同意,在不考虑实现的情况下编写接口的“感觉更好”。
【解决方案3】:

简单地说-

  1. 您在接口对象中明确记录了该模块的 API。它会让您的用户更清楚,也许会让您思考该界面中的内容
  2. 您可以在同一个对象上提供多个接口,并限制消费者可以执行的操作(例如只读与读写)
  3. 模拟框架利用接口,模拟类是一种非常强大的测试技术

【讨论】:

  • 1 和 2 是链接的,并且确实只在这个答案中提到,好点。
【解决方案4】:

事实上,使用接口代替类可以让你做三件事:

  1. 从实现中区分契约:契约是接口(它是你声明你要做的),而类显然是实现
  2. 提供轻松的替代实现。典型的例子是在不修改用户代码的情况下用另一种存储机制替换存储机制(比如用伏地魔项目替换 MySQL)
  3. 作为 2 的优点(这次很容易扩展到模型元素),接口允许您进行某种白盒测试:通过使用模拟框架(JMock、EasyMock 等),您将替换您的接口的实现,该行为可能是可疑的,通过所谓的“模拟”返回您对测试的期望。这将使您的测试不仅可以检查一个组件,还可以确保错误来自该组件,而不是来自其内部承包商(您给他的接口)。

【讨论】:

    【解决方案5】:

    这个使用接口的原因对我来说似乎也很奇怪。我看不出有什么性能优势,如果有,那可能完全不重要。

    也就是说,即使目前只有一种实现,也有一些使用接口的理由。以后扩展或提供替代实现可能更容易。 (尽管在任何体面的 IDE 中都有提取接口重构。)它可能更容易测试:如果您想测试仅通过接口使用其他类的类,您可以轻松地为其他类提供模拟对象。

    【讨论】:

    • 没错,我还没有考虑过测试方面,在这种情况下确实有用。但另一方面,它确实是关于具有并且将只有一个实现的大对象。
    【解决方案6】:

    这里有 2 个链接解释了您为什么要这样做:

    http://www.artima.com/lejava/articles/designprinciples.html http://pragmaticjava.blogspot.com/2008/08/program-to-interface-not-implementation.html

    它与执行性能无关(更多地与程序员(您)的性能有关),因为您将一个类的用户从其实现中解耦出来——除其他外,用于简化可测试性和可维护性。

    肯定不会有任何其他类实现这个接口。

    今年可能没有,但明年可能会有。

    【讨论】:

      【解决方案7】:

      接口在 Java 中被过度使用,部分原因是语言设计,部分原因是人们认为制作大量接口是好的设计。

      如果 Java 允许多重继承,抽象类将优于接口。 Scala 是一种新的 JVM 编程语言,具有 Traits 的概念,本质上是具有 MI 能力的抽象类。

      抽象类的优点是您可以在不破坏扩展它的现有类的情况下向抽象类添加行为。因此,抽象类作为扩展机制(插件)也比接口更好。

      不幸的是,JMock 及其兄弟鼓励使用大量接口进行 BDD 测试,但这不一定是真的,因为至少有几个库可以模拟具体对象。

      【讨论】:

        【解决方案8】:

        This question targeted C#,但我认为它也适用。投票率最高的答案是为每个类定义一个接口只是代码噪音

        【讨论】:

          【解决方案9】:

          有一个相对普遍的开发信条,几乎所有东西都应该有一个接口。据我所知,这要么是基于一种货物崇拜的心态,即“程序到接口,而不是实现”(这绝对不需要你在代码中到处乱扔接口),或者基于使用无法模拟具体类的旧模拟框架进行测试驱动开发。

          无视这些废话。

          【讨论】:

          • 您可以推荐哪个模拟框架来模拟给定的具体类?
          • @Thorbjørn:我一直在使用 Groovy 的内置模拟;但是 jMock 和 EasyMock 都有允许模拟具体类的扩展。 PowerMock 几乎可以模拟任何东西,包括最终类和方法
          【解决方案10】:

          还有另一种滥用接口的方法?

          使用接口没有明显的性能提升。 相反,它可能由于 RTTI(基于您的编译器的功能)而对性能产生负面影响

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-05-22
            • 1970-01-01
            • 1970-01-01
            • 2018-12-20
            • 1970-01-01
            • 2014-04-27
            • 1970-01-01
            • 2014-01-23
            相关资源
            最近更新 更多