Sunday, August 3, 2008

Program to an interface, not an implementation

In the introduction of the GoF book, the GoF mention an important principle of reusable object-oriented design. The principle is: "Program to an interface, not an implementation". The basic reason behind it is to achieve the flexibility in choosing different implementations at run-time as many times via the interface. This is achieved because of the polymorphism feature of the OO languages. The power of interfaces is best understood in design patterns. Most of the design patterns such as Strategy, State, Command, Abstract Factory Method are actually the above principle in practice. Now how do we try to abide by the principle? The best way is to strive for having method signatures with more generic, interface or parent class type method parameters and return types. Also it is advisable to declare class member variables to be of a more generic, interface or parent class type rather than a concrete implementation. The advantages of using interfaces (pure interfaces and/or abstract base classes) are as follows:
  • It is always painless to depend on interfaces. Client classes depending on the interfaces remain unaware of the concrete classes they use indirectly via the interface , as long as the concrete classes adhere to the interface that clients expect. This makes the clients more resilient to changes in implementation details.
  • The above aspect makes unit testing also very easy. In order to test a client class that depends on a complex computation exposed by an interface, we can create a mock stub object that implements the interface to replace the complex computation object.
  • Depending on interfaces has benefits even beyond just programming. The more we depend on concrete classes, the more complex dependency structures become, as a result our build scripts and build processes also tend to be more unwieldy.
Erich Gamma, one of the GoF, explains in an interview: "This principle is really about dependency relationships which have to be carefully managed in a large app. It's easy to add a dependency on a class. It's almost too easy; just add an import statement and modern Java IDEs like Eclipse even write this statement for you.Interestingly the inverse isn't that easy and getting rid of an unwanted dependency can be real refactoring work or even worse, block you from reusing the code in another context. For this reason you have to develop with open eyes when it comes to introducing dependencies. This principle tells us that depending on an interface is often beneficial."

5 comments:

Unknown said...

With such a theoretical advice, I would like some operational examples / references. Excuse me to be sceptic by nature, but without references your advice amount to as much as the known history of your blog : almost nothing.

Have you tried your advice on a large project (say some thousands or at least hundreds of classes) ?

Thank you.

André said...

I totally agree with you in the principle. Following this principle led me to some further thought I'd like to post here.
Your second argument on the other hand shouldn't be of any matter here. I think that's always wrong lead your design by testing-frameworks (mocks). It's clear that's it's easyer to test your code if it's based upon interfaces, but that shouldn't be an argument, that's only a consequence.
Furthermore I am convinced that it's bad to create an interface for its own sake to follow this principle. Interfaces augment the amount of code and get you more away from keeping it simple. My five cents here are 'use interfaces wisely, just when there are several implementations you want to hide' and 'proceed in an agile way, refactor to interface if you're convinced you need some now'.

Jacob Hookom said...

It's safer to program from an abstract class. Enforcing a java-interface type can cause more refactoring issues in that changes to that contract more easily break all implementations. Be careful on the use of interfaces. If you maintain both the client and the provider, then interfaces just add extra work in refactoring.

Anonymous said...

While I do both understand and appreciate the reasoning behind coding to interfaces, I let go of this dogma a while ago. I feel creating an interface just because you're expected to is premature abstraction.

I'm sure that when you look back at a previous project and count how many interfaces have only one implementation, you'll end up with a higher number than when you count the ones with more than one implementation. YAGNI in action.

About testing: in a typical web project, what's there to mock? Not the DAO layer (heck, I don't even have DAO layers anymore), since you're probably using an ORM tool that can switch to a test database for unit tests. The services? Same story. Only for external systems (this includes web services) having mock implementations makes sense. And when you realise that you do want to mock (worst case: while writing the test), it's early enough - you have no risk of not being able to refactor anymore.

thoughts said...

well , an interface as an object oriented concept represents the level of abstraction , which means the outer view of an entity , this concerns the Architect more than a programmer , on the other hand interface in java can be used to limit access to certain methods when u instantiate using the interface as object type , can any body tell me how to mock a final class ?