Tuesday, August 04, 2009

Coding an interface

Interfaces are a contract that a class must respect: a set of methods with specific signatures that should be implemented. Many components become dependent on interfaces that abstract away the concrete classes: mistakes have to be maintained and inherited.

In object oriented languages, an interface I corresponds to a set of methods (without body) which acts as a specification for classes. A class C that implements I must provide a body for every method that I has. The objects of class C are not only instanceof C but also instanceof I.
Interfaces are present in languages such as Java and Php. Since there's no limit to the number of interfaces that a class can implement, multiple inheritance is obtained via interfaces.

Here is a checklist for writing a clean interface:
  1. Keep methods number to a minimum. The complementary of an interface is an implementation, and every implementation is forced to provide code for the all the methods specified. If you are extracting an interface from a particular class, consider to only a cohesive set of public methods, which lead us to the next point. E.g. a Queue interface should have only two methods: put(...) and get(...). Specifiy a constructor or a length() method is not very purposeful.
  2. Segregate interfaces. The interface segregation principle says that a class should not depend on interfaces that it does not use. The meaning is that when an interface contains many methods, probably there are two or more interfaces which it should be broken into. E.g. Php SplQueue and SplStack could be interfaces instead of concrete classes, with only the purposeful methods included and SplDoubleLinkedList implementing both. As they are now they expose all the Iterator methods, which have no sense on a real stack or queue.
  3. No static methods. Interfaces provides a contract for polymorphism, and static methods are only global procedures under a nice name. Althoug some languages like php don't complain when encountering an interface definition which contains static methods, they should be avoided. E.g. resist the urge to put a static count() method on Queue to count the instantiated objects. Create a AbstractQueueFactory instead with a count() instance method.
  4. Abstract the meaning. Particularly if you are extracting an interface, pay attention to the method names: they have to carry an abstracted meaning and not implementation details, so some of them needs to be renamed. E.g. the Spl Iterator interface has generic methods like current() and key(); it does not assume anything on the keys of the elements which the iteration is performed on: in subclasses they can be filenames, array offset, object property names and so on.
  5. Do not tie to concrete types. Depending on an interface decouple a system from the implementation of a particular service, but if the interface depends on other concrete classes the advantage is lost; the only classes cited in an interface definition should be Value Objects (like java String or php Datetime) or Entities (the example User class, without injected services). E.g. an Authenticator interface with a method signature which contains a Zend_Db object is useless.
I hope you'll be writing small and cohesive interfaces now. Let me know what are your guidelines for coding interfaces in the comments.

No comments: