Elizabeth Keogh has been writing a couple of articles on naming of interfaces. In the process, she’s highlighted a more important issue: granularity of types.
IMHO opinion, base types (those that don’t inherit from other types) should be fairly fine grained. You can always aggregate types together to get coarse-grained types, but you can’t go back the other way.
(Types are represented in Java by both classes and interfaces. However, most of these comments apply to interfaces more so than classes)
What do I mean by fine-grained? Simple: not many methods, all of which are logically consistent. Clients to a type (either a caller or an implementer) should care about the vast majority of the methods.
This gives a heuristic for when you should extract a new type – when you have a client that only cares about a subset of the entire type. Elizabeth gave a good example: a
Gui type and an
Engine type need to talk to each other via
ReportEvents. Elizabeth wants to create an
EventQueueHandler. With the coarse grained interfaces she has now, her
EventQueueHandler class needs to implement both the
Engine types – ouch! All it cares about is one method on each, and it needs the rest of the baggage!
The right way to solve it is to extract two new types:
EventQueueHandler implements both. The
Gui implements the
ReportEventListener, and the
Engine implements the
RequestEventListener. (Alternatively, the Event concept could be made more generic, at the cost of some typesafety)
Extract new types when a client only cares about a subset of the existing type