I’ve been long wondering why I should use interfaces. Hold on, this post is going to be somewhat long ;)
Of course, there is the most commonly known fact: you can specify one interface for several implementations. A good example of this is the Java List interface, with its subclasses: ArrayList, LinkedList, Vector…
But I recently discovered two other reasons. Consider these classes I wrote a few days ago in PHP:
class Statement {
public function __construct($query);
public function execute(array $args);
public function fetch();
}
class ResultSet {
public function __construct(Statement $stmt);
public function hasNext();
public function next();
}
A ResultSet is created from a freshly executed Statement, taking its data from the Statement::fetch() method. But don’t you see a little design flaw here ? Doesn’t something bother you a little bit ?
Yes, you got it! We just gave the ResultSet class the right to execute a Statement, and that’s really bad!
Now guess what… we are going to use an interface to correct this design error. (changes are in bold)
interface Fetchable {
function fetch();
}
class Statement implements Fetchable {
public function __construct($query);
public function execute(array $args);
public function fetch();
}
class ResultSet {
public function __construct(Fetchable $ftch);
public function hasNext();
public function next();
}
Now, our ResultSet class doesn’t have the ability to execute a Statement anymore.
This is called “Defensive Programming”, or at least it’s a bit of it. Defensive Programming is a kind of coding mindset, aiming to reduce the risk that other people, or even you, make mistake while coding. With the above example, this is done by restraining the actions your code is allowed to do.
The last reason to use I found (but I bet there are lot more), it that it will help you to perform Test Driven Development (TDD). Let’s take the above example once again. I want to test this ResultSet class. One way to test it would be to create a select statement, execute it and create a ResultSet object with it.
Ow, wow, poor database, poor testers, who will have to ensure the db is not empty, poor developer who will have less quality tests, poor…
With interfaces, however, I can create some stupid class, let’s say DummyFetchable, that would implement this interface. And simply give this class to my ResultSet: I swear, this good guy will see nothing!
class DummyFetchable implements Fetchable {
public function fetch();
}
class ResultSetTester {
public function testResultSet() {
$source = new DummyFetchable();
$rs = new ResultSet($source);
… and test this out, without killing your db :)
}
}
Hope this post has been of some use to some people :) Let’s summarize it all:
- one external behavior, several implementations;
- Defensive Programming;
- Unit Testing;
- and certainly more, please let me know :)