Hi,
I keep coming across this term
"Program to an interface"What exactly does it mean? A real life design scenario would be highly appreciated.
Thanks
Hi,
I keep coming across this term
"Program to an interface"What exactly does it mean? A real life design scenario would be highly appreciated.
Thanks
I think this is one of Erich Gamma's mantras. I can't find the first time he described it (before the GOF book), but you can see it discussed in an interview at: http://www.artima.com/lejava/articles/designprinciples.html
"Programming to an interface" happens when you use libraries, other code you depend upon in your own code. Then, the way that other code represents itself to you, the method names, its parameters, return values etc make up the interface you have to program to. So it's about how you use third-party code.
It also means, you don't have to care about the internals of the code you depend on, as long as the interface stays the same, your code is safe (well, more or less...)
Technically there are finer details, like language concepts called "interfaces" in Java for example.
If you want to find out more, you could ask what "Implementing an Interface" means...
Here's a design scenario, involving ... pizza:
http://fatagnus.com/program-to-an-interface-not-an-implementation/
Real-world examples are applenty. One of them:
For JDBC, you are using the interface java.sql.Connection
. However, each JDBC driver provides its own implementation of Connection
. You don't have to know anything about the particular implementation, because it conforms to the Connection
interface.
Another one is from the java collections framework. There is a java.util.Collection
interface, which defines size
, add
and remove
methods (among many others). So you can use all types of collections interchangeably. Let's say you have the following:
public float calculateCoefficient(Collection collection) {
return collection.size() * something / somethingElse;
}
And two other methods that invoke this one. One of the other methods uses a LinkedList
because it's more efficient for it's purposes, and the other uses a TreeSet
.
Because both LinkedList
and TreeSet
implement the Collection
interface, you can use only one method to perform the coefficient calculation. No need to duplicate your code.
And here comes the "program to an interface" - you don't care how exactly is the size()
method implemented, you know that it should return the size of the collection - i.e. you have programmed to the Collection
interface, rather than to LinkedList
and TreeSet
in particular.
But my advice is to find a reading - perhaps a book ("Thinking in Java" for example) - where the concept is explained in details.
Every object has an exposed interface. A collection has Add
, Remove
, At
, etc. A socket may have Send
, Receive
, Close
and so on.
Every object you can actually get a reference to has a concrete implementation of these interfaces.
Both of these things are obvious, however what is somewhat less obvious...
Your code shouldn't rely on the implementation details of an object, just its published interface.
If you take it to an extreme, you'd only code against Collection<T>
and so on (rather than ArrayList<T>
). More practically, just make sure you could swap in something conceptually identical without breaking your code.
To hammer out the Collection<T>
example: you have a collection of something, you're actually using ArrayList<T>
because why not. You should make sure you're code isn't going to break if, say, you end up using LinkedList<T>
in the future.
It basically means that the only part of the library which you're going to use you should rely upon is it's API (Application programming interface) and that you shouldn't base your application on the concrete implementation of the library.
eg. Supposed you have a library that gives you a stack
. The class gives you a couple of methods. Let's say push
, pop
, isempty
and top
. You should write your application relying only on these. One way to violate this would be to peek inside and find out that the stack is implemented using an array of some kind so that if you pop from an empty stack, you'd get some kind of Index exception and to then catch this rather than to rely on the isempty
method which the class provides. The former approach would fail if the library provider switched from using an array to using some kind of list while the latter would still work assuming that the provider kept his API still working.
Polymorphism depends on programming to an interface, not an implementation.
There are two benefits to manipulating objects solely in terms of the interface defined by abstract classes:
This so greatly reduces implementation dependencies between subsystems that it leads to this principle of programming to an interface.
See the Factory Method pattern for further reasoning of this design.
Source: "Design Patterns: Elements of Reusable Object-Oriented Software" by G.O.F.
To put it simply, instead of writing your classes in a way that says
I depend on this specific class to do my work
you write it in a way that says
I depend on any class that does this stuff to do my work.
The first example represents a class that depends on a specific concrete implementation to do its work. Inherently, that's not very flexible.
The second example represents a class written to an interface. It doesn't care what concrete object you use, it just cares that it implements certain behavior. This makes the class much more flexible, as it can be provided with any number of concrete implementations to do its work.
As an example, a particular class may need to perform some logging. If you write the class to depend on a TextFileLogger, the class is forever forced to write out its log records to a text file. If you want to change the behavior of the logging, you must change the class itself. The class is tightly coupled with its logger.
If, however, you write the class to depend on an ILogger interface, and then provide the class with a TextFileLogger, you will have accomplished the same thing, but with the added benefit of being much more flexible. You are able to provide any other type of ILogger at will, without changing the class itself. The class and its logger are now loosely coupled, and your class is much more flexible.
An interface is a collection of related methods, that only contains the signatures of those methods - not the actual implementation.
If a class implements an interface (class Car implements IDrivable
) it has to provide code for all signatures defined in the interface.
Basic example:
You have to classes Car and Bike. Both implement the interface IDrivable:
interface IDrivable
{
void accelerate();
void brake();
}
class Car implements IDrivable
{
void accelerate()
{ System.out.println("Vroom"); }
void brake()
{ System.out.println("Queeeeek");}
}
class Bike implements IDrivable
{
void accelerate()
{ System.out.println("Rattle, Rattle, ..."); }
void brake()
{ System.out.println("..."); }
}
Now let's assume you have a collection of objects, that are all "drivable" (their classes all implement IDrivable):
List<IDrivable> vehicleList = new ArrayList<IDrivable>();
list.add(new Car());
list.add(new Car());
list.add(new Bike());
list.add(new Car());
list.add(new Bike());
list.add(new Bike());
If you now want to loop over that collection, you can rely on the fact, that every object in that collection implements accelerate()
:
for(IDrivable vehicle: vehicleList)
{
vehicle.accelerate(); //this could be a bike or a car, or anything that implements IDrivable
}
By calling that interface method you are not programming to an implementation but to an interface - a contract that ensures that the call target implements a certain functionality.
The same behavior could be achieved using inheritance, but deriving from a common base class results in tight coupling which can be avoided using interfaces.