我正准备用鸭子类型语言 (Groovy) 编写我的第一个应用程序。
如果我要用静态类型语言编写相同的应用程序,那么我需要定义一些接口。显然,由于 Groovy 中的鸭子类型,它们实际上并不是必需的。目前,我认为将它们定义为需要在各种对象中实现的方法的文档可能是有意义的。我错过了重点吗?
我正准备用鸭子类型语言 (Groovy) 编写我的第一个应用程序。
如果我要用静态类型语言编写相同的应用程序,那么我需要定义一些接口。显然,由于 Groovy 中的鸭子类型,它们实际上并不是必需的。目前,我认为将它们定义为需要在各种对象中实现的方法的文档可能是有意义的。我错过了重点吗?
我最近一直在 SO 上阅读此内容(我现在找不到链接,但它是“为什么动态语言很好?”的帖子之一,以及 S. Lott 的一个重要答案,有很多评论) ,答案是:
你可以。特别是在 Groovy 中,您可以在 Java 或 Groovy 中定义接口并实现它们。然而,对于鸭子类型(Groovy 允许但也允许显式类型),许多人会说“为什么要麻烦?” 源是它自己的文档,接口在源中,“使用源”等。
就个人而言,这让我发疯——我喜欢 Java 给我的编译时(或者实际上是开发时)检查,但这是另一个争论。如果您使用 Groovy,那是因为您想编写出自鸭式打字的精巧简洁明了的代码。在这种情况下,除非必要,否则应避免使用接口。
它们在哪里是必要的?在程序的各个部分之间,以及在程序的公共 API 中(尽管它们也可以是抽象类)。否则,我会说你应该尽量避免在鸭式语言中使用它们。这迫使您编写有关类的文档,或者编写非常清晰的代码,以至于它们是同一回事。
我认为这是一种糟糕的做法,但是这是向动态语言转变的范式的一部分。而且我认为,如果您避免将接口与实现充分分离,您就会理解其背后的“原因”。我仍然没有,尽管它与不重复代码(保持 DRY)有很大关系。
Edit: Got some clarity away from the computer :) One of the main reasons NOT to separate interface from implementation is so that you move away from a dependence on types. In duck-typing, as you know, I don't care if it's an implementer of the Vehicle
interface (for instance). I only care if it has a go
method with 2 params. So the more you work with interfaces, the more you are writing Java in Groovy ("you can write Fortran in any language"). This should be avoided, as new languages open you up to new stuff.
我不熟悉 groovy,但总的来说,不,您不需要用松散类型的语言定义接口。
您会重复自己,如果您需要更改方法签名,那么您需要在两个地方进行,而不是一个。
尽管接口确实有一些用作文档的用途,但在松散类型的语言中,大多数编码人员不会期望接口,因此如果他们需要文档,他们不会去搜索接口。
大多数动态语言都有很好的 IDE 可供它们使用,具有方法完成功能,这进一步减少了对单独接口的需求。
方法可以在动态语言中绑定和取消绑定。因此,您可以并且很可能最终会得到不符合接口的对象。拥有一个单独的界面最终可能会使阅读您的代码的人感到困惑。
定义接口是一种代码内文档。使用接口,您可以明确声明您期望从类中获得什么来满足您的需求。
PS:groovy不是我的语言,所以我其实根本不知道是否可以在那里定义接口。
In some cases yes. I have an example where I'm creating a Groovy class that gets injected into a Java class by Spring. I created an interface using generics like this:
//interface injected to a java class
public interface SomeInterface {
<T> T getSomething(int version, Long id);
}
Then the groovy implementation looks like this:
//Groovy impelentation
class SomeInterfaceImpl implements SomeInterface {
def getSomething(int version, Long id) {
//use duck typing to create similar objects based on version
}
}
My example is that I'm using JAXB and XJC to create objects from an XML schema and using them in a Jersey restful web service. I'm versioning the web service and the changes are enough to version, but there's still a lot of code that can be reused. Using interfaces proved to be problematic, so I used Groovy instead and moved all the similar logic to the above mentioned Groovy class with duck typing. The objects are mostly the same with some some changes so duck typing with an interface to inject in the Java class works perfectly.