Saturday 14 February 2009

Item18: Prefer interfaces to abstract classes

For defining types that permits multiple implemetations you have two choices (with their pros):
  • interfaces: support multiple inheritance

  • abstract classes: can contain implementations
Usecases which prefer interfaces:
  • retrofitting existing classes (example of the JDK, Comparable Interface introduction)

  • defining mixins (mixin is not a form of specialization but is rather a means to collect functionality), e.g. again the Comparable Interface is a good example for that…

  • Construction of nonhierarchical type frameworks

  • Functionality enhancements via wrapper classes (see Item 16)
Yet interfaces can not contain method implementations (e.g. default implementation or assistance/helper methods for implemetors of this interface). However exactly in this case a abstract class (a skeleton implementation for the interface) comes into play ;-). By convention they have a common "Abstract" prefix in the classname (e.g. AbstractXYZ for Interface XYZ). The idea is to use (and reuse) the abstract class better as implementation helper for an interface rather than as a type definition. Weaving the abstract skeleton class into the concrete class can be done via inheritance of via delegation. Note however that there is no private inheritance statement in Java (C++ there IS private inheritance and it communicates the intention very obvious as implementation inheritance). Does anybody know why there is no private inheritance in Java ?

As abstract skeleton classes are ideal candidates for inheritance (refinement of the default helper implementation) we should document the class as described in Item 17.

One special case of a skeleton class is the "Simple" Implementation which is a non-abstract helper class with a common "Simple" prefix. However I am unsure if this is a common prefix or convention. Even in the JDK source I only found .SimpleEntry and .SimpleImmutableEntry as Simple inner implemetation classes. Does anybody know if this is a common convention and often used ? My impression is that AbstractXYZ means the skeleton approach is used much more often.

Usecases which prefer abstract classes (as type definition)
  • it is far easier to evolve and abstract class than an interface.
    You can simply add the new method with a default implementation and all classes which inherit from that class (and get recompiled ! ;-) will inherit that default implementation. Impossible with interfaces.

  • Workaround for interfaces would be to add the method declaration to the interface and a default method implementation to the skeleton class, however classes NOT inheriting from that skeleton class will break.
However the topic with evolving interfaces and abstract classes or better evolving API in general is much more complicated as the following article shows: (which IIRC mentioned also in another Item recently)

http://wiki.eclipse.org/index.php/Evolving_Java-based_APIs

http://wiki.eclipse.org/Evolving_Java-based_APIs_2

Josh also mentioned that changing an interface (once it is released) is nearly impossible. Well I think everybody, who has clients which are using your written software (programming against your API) has learned this is some way (maybe a painful) way. So get it right in the first place. But how to do this ? I recently read a book "Framework Design Guidelines" (okay from the other side, M$ ;-) but some tips about "how to create and especially test with Clients how good and understandable it the API" are really worth to read IMO.

http://www.amazon.com/Framework-Design-Guidelines-Conventions-Development/dp/0321246756

Bernhard Merkle

No comments: