【问题标题】:Java interfaces - What exactly is in the contract? [closed]Java 接口 - 合同中到底有什么? [关闭]
【发布时间】:2012-03-30 18:04:38
【问题描述】:

我知道并理解 Java 中接口的价值。您对接口进行编码,然后您可以更改您的实现,而无需使用该接口更改任何代码。通常,术语“合同”与接口一起使用。我理解它的方式是接口定义了应用程序和实现之间的“合同”。

所以,当我创建一个实现时,我必须履行合同。我的问题是,我必须履行的合同中究竟有什么内容?

显然,您至少必须提供与接口具有相同签名的方法。否则代码将无法编译。这就是“合同”的全部内容吗?好像应该还有更多。

例如,我读过一些文章,讨论了测试接口与测试特定实现的价值,或者两者兼而有之。我认为对接口进行测试很有价值,这样您就可以知道哪些输入具有哪些预期输出。在我看来,这也是接口“合同”的一部分。接口的每个实现都应该从相同的输入产生相同的输出。显然没有办法在代码中强制执行这个契约,但是可以通过测试用例来强制执行。我在这里的想法是不是错了?

最后,实现的副作用是什么?在这里,我主要谈论作为实现的一部分可能发生的任何持久性。假设我有一个在执行操作时将一些记录保存到数据库的实现。这会以某种方式成为接口“合同”的一部分吗?如果是这样,你怎么能执行这个合同?从接口级别,我不知道实现实际上在做什么。我只知道我给它输入,它给我一个输出,我可以测试它。发生的任何持久性是否也被视为“输出”?如果是这样,我只是不明白如何测试和执行它。我是持久性无知的支持者,所以我可以知道某些东西应该被持久化,但我不知道它是如何被持久化的。所以,我只是不知道什么时候真正持续存在。如果你的界面有一些简单的 CRUD 操作可能会很简单,但我想考虑更复杂的界面。

我希望我的问题是有道理的,并且有人可以提供一些好的反馈。我想笼统地讨论这个问题,但如果不清楚我在说什么,我可以提供一个具体的例子。

【问题讨论】:

  • 要测试“契约”,为接口编写单元测试,每个实现都必须首先调用它(有办法做到这一点)。如果需要检查特定于实现的部分,那么接下来就是。一般来说,您希望所有测试都尽可能地减少副作用。因此,在测试持久性的东西时,您通常使用模拟对象代替(实际上)持久化对象;从调用代码片段来看,它是一个持久化对象——它只是从未出现在数据库中。
  • en.wikipedia.org/wiki/Design_by_contract 寻找“每个方法的合同通常会包含以下信息……”并不严格适用于 Java,但是是的……
  • 文档。这就是指定给定接口合同的许多额外信息的原因。注意:“接口的每个实现都应该从相同的输入产生相同的输出。”如果每个实现代表不同的书,那么接口 IBook 和 GetPage(1) 调用就不会是真的......
  • @X-Zero 我了解模拟对象的价值,我正在使用一个。我的观点是,在我的接口测试中,我所拥有的只是接口。我使用 Spring 为我配置它,但在测试本身中,它不知道它是如何配置的。那么,当它不知道它是如何配置为持久化数据时,我将如何确保某些东西持久化(即使它持久化在模拟对象中)。

标签: java interface interface-implementation


【解决方案1】:

我认为“合同”和“接口”的共同点很少。

界面就像一扇门。 一扇门可以通过典型的人类,但不能通过大象、长颈鹿或汽车。

合同是您可以通过门确保 只有女性、男性或软件开发人员会来。

所以合约定义了行为,而接口定义了传递的信息

【讨论】:

  • 好的,这是一个很好的说明。我想我的问题是,如何执行行为?只有在测试特定实现时才有可能吗?或者你能强制执行界面“行为”吗?
【解决方案2】:

我认为您对“合同”一词的理解太过分了。

“Eiffel”有一个非常具体的“契约式设计”理念。就个人而言,我认为其他语言会从类似的东西中受益。

非正式地,您当然可以将 Java 的“接口”视为一种“契约”。您对 Java 接口的定义当然很好:

至少您必须提供具有相同签名的方法 界面。否则代码将无法编译。

问:这就是“合同”的全部含义吗?

A:可能不会。这完全取决于您如何定义“合同”;)

但是,恕我直言,Java 接口是一个更比可怕的 C++“多重继承”更清晰的特性。两者背后的主要动机之一是支持“mixins”:

同样,Java 接口也提供了一个干净、相对简单、类型保存的解决方案来支持“callbacks”。

最终建议:请考虑“接口”和“抽象类”的区别。这也可能让您更深入地了解 Java 接口,以及如何在自己的代码中有效地使用它们:

Interface vs Abstract Class (general OO)

【讨论】:

  • Java接口如何实现mixins的概念,看到它们不提供实现?
  • 我猜这篇文章源于尝试为我的界面编写测试用例。在最高级别,我的问题可能是接口测试应该实际测试什么?仅根据传入的参数返回值?可能会更改传入的对象?测试中是否应该有任何部分来确保实现某些行为?
【解决方案3】:

因此,合同是方法签名+与函数/类相关的任何文档。从中得出的结论是,接口与 java 关键字 interface 的含义不同。接口是允许您与另一个系统交互的任何东西。那么对于你如何履行声明为这样的函数的契约的问题:

    /**  Throws IllegalArgumentException if s is null.    
Converts the input <b>s</b> into an {@link Integer}  */
    function go(String s);

您需要编写如下实现:

function go(String s)  
{  
    if(null == s) throw new IllegalArgumentException();  
    int i = Integer.parseInt(s);
}  

做作是的,但这应该解释如何执行合同并遵守它。

【讨论】:

  • 在这个简单的案例中,很容易测试并确保合同得到满足。在坚持的情况下,似乎会更加困难。这是否也意味着您将记录需要发生的持久性?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 2017-02-17
  • 1970-01-01
相关资源
最近更新 更多