Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the right level of Interface granularity

I'm doing some API design work at present, involving the specification of a number of interfaces as abstractions that will later be implemented by various concrete classes.

As it happens, I am using Java, but I think the question is relevant to any language that supports a similar interface concept.

I've noticed that there is often an option between:

  • Making a large interface with a full range of methods
  • Making multiple interfaces each containing a subset of the full range of methods (a single concrete class would probably have to implement several or all of these interfaces)

What are the pros / cons of each approach?

like image 265
mikera Avatar asked Jan 21 '11 14:01

mikera


3 Answers

The pro of splitting out the interface is that you can divide the methods into groups of responsibilities that make sense to be together. The con is the your interface is now split into a bunch of smaller ones that one class might be implementing.

I would recommend splitting the interface out where it helps readability and no further. If you have one class that is implementing 10 interfaces, either those interfaces need to be combined into one, or possibly the class is taking to much responsibility and it really needs to be two or more classes.

like image 87
jzd Avatar answered Oct 23 '22 14:10

jzd


In terms of anti-patterns I would say that too much interfaces may lead to the so called Yo-yo-problem:

http://en.wikipedia.org/wiki/Yo-yo_problem

And putting everything in a single interface may create the God object:

http://en.wikipedia.org/wiki/God_object

You should find your place somewhere in between :)

Good luck!

like image 29
Lachezar Balev Avatar answered Oct 23 '22 14:10

Lachezar Balev


One issue not mentioned yet: interfaces which put items into a collection should be separate from those which take items out; a combined interface should inherit from both. Segregating interfaces in this way allows for covariance and contravariance. For example, a ReadableBunch(Of ToyotaPrius) may be safely passed to a routine expecting a ReadableBunch(Of Car) [since an object that gives out instances of ToyotaPrius will in so doing give out instances of Car] , and a WritableQueue(Of Car) may be safely passed to a routine expecting a WriteableQueue(Of HondaCivic) [since an object that can accept a Car will by definition accept a HondaCivic].

I don't know if this type of covariance and contravariance mean anything in Java, but since the question was tagged language-agnostic, the issue should be considered by anyone coding for platforms that support covariance and contravariance (e.g. .net)

like image 4
supercat Avatar answered Oct 23 '22 15:10

supercat