【发布时间】: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