The Forkless Philosopher
Programming To An Interface
General principle
Programming To An Interface describes the practice of never using concrete classes as types for attributes and arguments, but to use abstract classes instead. That way, you can later change the concrete implementation without having to change the code in all the places where it is used. And it also greatly facilitates unit testing.
Example
Let me give you an Example. Think of the method:
if ( con.isConnected() ) {
string p = con.getPage( url );
[...]
}
}
How do you unit test it, if you do not have a web connection? The answer to this is: develop a mock object that acts like
CWebConnection
but always
returns true when isConnected()
is called and a fixed example page
on getPage()
calls. Quickly written, no problem. Only you can't pass
it to extractSharePriceFrom
because extractSharePriceFrom
expects a CWebConnection
and not a CMockWebConnection
.
And here Programming To An Interface comes to your rescue.
The first thing to do is to define an interface, i.e. list the public methods
all implementations of a web connection must offer because they are used
in the code at someplace or other. In other words: create an abstract class
IWebConnection
.
Next, make your existing web connection implementation inherit from
that abstract class: CWebConnection : IWebConnection { ... }
.
Now you can change the method's signature:
string extractSharePriceFrom(string url, IWebConnection& con)
{ ... }.
Finally, you create your mock class as also inheriting
from the abstract web connection interface:
CMockWebConnection : IWebConnection { ... }
. And from now
on, whether you feed extractSharePriceFrom(...)
an instance of
CWebConnection
or an instance of CMockWebConnection
doesn't matter (at least in the sense that it doesn't break your build).
And you can write your unit tests.
Extreme Abstraction
In "Prefactoring" (O'Reilly, 2005) Ken Pugh takes the concept even
further: calling it extreme abstraction, he advocates avoiding even
build-in types like integer or string completely for any domain-specific
data and to use classes instead. So, instead of int price
you
use CPrice price
or, since we are programming to an interface,
IPrice price
. Even if CPrice
internally uses
an int
to store the price. But if at a later time your representation
of price needs to change, you only have to do it in the concrete implementation of
whaterver class you have that fulfills IPrice
's contract, and not all
over your code.
Exceptions To The Rule
For value classes, i.e. classes that have no other purpose than to be a container for various related values, it is acceptable to do without an explicit interface class. Like structs, they are an interface in themselves.