Should I define interfaces in Duck Typed languages

2019-03-15 02:38发布

问题:

I'm just about to write my first application in a duck typed language (Groovy).

If I was to write the same application in a static typed language then I would need to define some interfaces. Obviously because of the duck typing in Groovy they are not actually required. At the moment I am thinking that it might make sense to define them anyway as documentation of the methods that need to be implemented in the various objects. Am I missing the point?

回答1:

I've been reading on this recently here on SO (and I can't find the link right now, but it's one of those "why are dynamic languages good?" posts, and a big answer by S. Lott with many comments), and the answer is:

You could. In Groovy especially, you can define interfaces in Java or Groovy and implement them. However, with duck-typing (which Groovy allows but also allows explicit types) many people would say "why bother?" The source is it's own documentation, the interface is in the source, "use the source" etc.

Personally, this drives me mad -- I love the compile-time (or really, dev-time) checks Java gives me, but that's another debate. If you're using Groovy, it's because you want to write that brilliantly concise and clear code that comes from duck-typing. In that case, interfaces are to be avoided except where necessary.

Where are they necessary? Between parts of a program, and in the Public API for a program (though they can be abstract classes, too). Otherwise, I would say that you should try to avoid them in duck-typed languages. This forces you to write the docs on the classes, or write code that is so clear that it's the same thing.

I think this is terrible practice, HOWEVER this is part of the paradigm shift towards dynamic languages. And I think that if you avoid separating interface from implementation enough, you'll understand the 'why' behind it. I still do not, though it has a lot to do with not repeating code (keeping 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.



回答2:

I'm not familiar with groovy, but in general, no, you don't need to define interfaces in loosely typed languages.

  1. You would be repeating yourself, if you need to change a methods signature, then you need to do it in two places, not one.

  2. Although interfaces do have some use as documentation, in a loosely typed language, most coders will not expect an interface, and therefore will not go searching for an interface if they need documentation.

  3. Most dynamic languages have good IDE's available for them, with method completion, which further diminishes the need for a separate interface.

  4. Methods can be bound and unbound in dynamic languages. Therefore, you can, and probably will, end up with objects that do not adhere to the interface. Having a separate interface could end up confusing people reading your code.



回答3:

Defining an interface is a kind of in-code documentation. With an interface you declare explicitly what you expect from the class to satisfy your needs.

PS: groovy is not my language, so I actually don't know whether it's possible to define interfaces there at all.



回答4:

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.