16/11/2008

Item 52: Refer to objects by their interfaces

(A side related note first: I still need to get the 2nd edition of Effective Java. The 1st edition copy I have is very well-read, though! Highly recommended for all Java programmers. Edit: I did buy the book in the end; InformIT sells non-DRM PDF copies, so yay!)

Anyway, this is a short rant about one of my personal peeves. To put it succinctly, I'll borrow a line out of Effective Java: Item 52: Refer to objects by their interfaces. I believe this so strongly that I've used that as the post title too. :-)

Let's motivate with an example:


Vector<Number> getPrimes(Number from, Number to);
Collection<Number> getPrimes(Number from, Number to);

Which one of the two would you prefer for your interface? Without reservation, I'd prefer the second one, because it doesn't name a concrete return type, thus giving the implementation more flexibility; for example, instead of having to create a Vector, you could use sets, singletons (from Collections), arrays (with a List view created by Arrays.asList), or even a custom type, as long as it fulfils the Collection interface. Clients that want to use Vector could simply construct one from the returned collection.

The same applies to incoming parameters in an interface too. For example:


Number sum(Vector<Number> numbers);
Number sum(Collection<Number> numbers);

Which one do you prefer here? (It could be argued that List should be preferred to Collection if the order of the numbers is significant; however in this example of summing, addition is commutative so this doesn't matter.) To use the first signature would put a burden on your interface's clients; there is no easy construction syntax for making a Vector, whereas on the other hand there are easy ways to express creation of lists (Arrays.asList is variadic), singletons, etc.

In summary, where there are interface types you can use for incoming parameters and return values, you should definitely prefer them. Concrete types are for instantiation only, or perhaps for use in legacy hierarchies that don't have interface types. (For instance, I consider it totally broken that Reader and Writer are abstract classes instead of interfaces.)

No comments: