An interface separate from its implementation filters the pertinent information a caller cares about.
In languages that permit you to declare interface signatures independently from their implementation, typically for constraint/type checking, you've got a handy place to document the interface with comments.
Whilst it can be argued (correctly) that the type checking information is really DerivedInformation
and is annoying to maintain, it's generally worth it just for the added documentation benefit. I'm not saying to write MassiveFunctionHeaders
, but FileHeaders
by themselves mixed with small CrcCard
like method comments go a long way to explaining how to use a system.
The main idea here is that you don't want to inundate your reader at this level with information about the implementation. All she wants to know is how to use your class. Typically you're only publishing the public interface as well (cf. EmphasizeImportantInformation
), once again improving the signal to noise ratio.
So, with a separate interface you can a) identify the public interface cleanly to the caller, b) document what the caller needs to know to use your code.
Typically you'll find the caller will jump into the implementation anyway, but at least this way she knows where to go and has a good module-wide understanding first instead of having to page up/page down through lots of code to get an idea of what's going on.
Just an example of GroupRelatedInformation
In a language like JavaLanguage
, for which this method is applicable, what advantage does this give us? Shouldn't JavaDoc
serve as the public interface layer? Doesn't creating an interface for every class just increase the count of class by a factor of ~2 without any visible benefits?
In other words, a violation of OnceAndOnlyOnce.
There are also disadvantages to this in terms of code traceability. When checking a control flow, these interfaces become dead end walls, making it hard to trace the flow of the code.
The only major advantage I see is the ability to use MockObject
s, which is big plus but not mentioned here.
The purpose of an interface in Java is to allow one to derive multiple child classes. If only one class is needed, then there is no value to type the same information twice (remember, this is one of the gripes against C/C++, the requirement to define each function twice). I agree that use of a MockObject
is a valid reason to define multiple child classes, but I hasten to add that it is usually more beneficial to test with the real class whenever feasible. Don't create interfaces just to create interfaces, let the design evolve and create an interface when the design demands one.
The ability to use MockObject
's underlies one of the greatest benefits of separating an interface from its implementation: the ability to "swap out" an implementation with another without affecting dependent clients of its interface(s). This is the core concept being used with mock objects; the client expects an interface that behaves in a certain manner (see also: LiskovSubstitutionPrinciple
), and nothing more. As long as the mock object fulfills the contract of the interface that its mocking, the clients of the interface could care less how it does it.
Take the idea of a standard Collection interface, for example. The basic and commonly-accepted purpose of a Collection is for clients to have the ability to add, remove, iterate over, and look up a set of objects. A class (call it Simple
Class) may expose, as part of its interface, a Collection. To a client of Simple
Class, the Collection is just that: a basic Collection instance.
Class could actually be instantiating a more feature-full implementation of Collection for its own purposes. This implementation could do any number of things that Simple
Class requires for the proper functioning of its own internal state. Some additional functionality of the Collection implementation used by Simple
Class could include raising events when an item is added/removed, as well as providing additional members on its interface for other set-based operations.
See Also: ImplementationIndependenceLimits