Faoileag's Nest

My Home On The Net

Faoileag On...

Programming To An Interface

General principle

Programming to an interface describes the practice of never using concrete classes as types for members and arguments, but to use abstract classes instead.

There are three reasons why programming to an interface can help you write better code:

  1. If you want to make use of dependency injection, programming to an interface is mandatory.
  2. Should you ever exchange the concrete class X you are using with another one (Y), you don't have to go through all your classes and update the signatures of all the classes where class X is used.
  3. It also facilitates unit testing, because you can use mock classes instead of the real ones.

Example

Let me give you an Example. Think of the method:

double extractSharePriceFrom(string& url, CWebConnection& con) {
  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 that returns a hardcoded 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 that is where 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 somewhere in your code. This can be a pain, especially if your editor does not provide tools like "find usages" to call on your methods..
Next, build a class around these methods and make that class abstract. In Java, you declare an interface class, in C++ you can make classes abstract by telling the compiler that no definition is following a declaration by setting the method to zero: void myMethod = 0;

If the programming language of your choice does not mandate it anyway, it is nevertheless helpful to give interface classes names that tell that they define an interface: IWebConnection or AbstractWebConnection are common ways to do it.

Now you must make your existing web connection class inherit from the abstract class. That should be simple, as everything else can stay as it is.

Finally, you have to change the signatures of all methods that use your old class as an argument. In the example given, change

double extractSharePriceFrom(string& url, CWebConnection& con);

into

double extractSharePriceFrom(string& url, IWebConnection& con);

And now your code has just become much better testable, because...

... you can now create a mock connection class that inherits from IWebConnection that you can feed into double extractSharePriceFrom(string& url, IWebConnection& con); from your unit tests. Happy testing!

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 integer 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 already are an interface in themselves.