What does it mean to "program to an interface"?

Viewed 210894

I have seen this mentioned a few times and I am not clear on what it means. When and why would you do this?

I know what interfaces do, but the fact I am not clear on this makes me think I am missing out on using them correctly.

Is it just so if you were to do:

IInterface classRef = new ObjectWhatever()

You could use any class that implements IInterface? When would you need to do that? The only thing I can think of is if you have a method and you are unsure of what object will be passed except for it implementing IInterface. I cannot think how often you would need to do that.

Also, how could you write a method that takes in an object that implements an interface? Is that possible?

33 Answers

There are some wonderful answers on here to this questions that get into all sorts of great detail about interfaces and loosely coupling code, inversion of control and so on. There are some fairly heady discussions, so I'd like to take the opportunity to break things down a bit for understanding why an interface is useful.

When I first started getting exposed to interfaces, I too was confused about their relevance. I didn't understand why you needed them. If we're using a language like Java or C#, we already have inheritance and I viewed interfaces as a weaker form of inheritance and thought, "why bother?" In a sense I was right, you can think of interfaces as sort of a weak form of inheritance, but beyond that I finally understood their use as a language construct by thinking of them as a means of classifying common traits or behaviors that were exhibited by potentially many non-related classes of objects.

For example -- say you have a SIM game and have the following classes:

class HouseFly inherits Insect {
    void FlyAroundYourHead(){}
    void LandOnThings(){}
}

class Telemarketer inherits Person {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}
}

Clearly, these two objects have nothing in common in terms of direct inheritance. But, you could say they are both annoying.

Let's say our game needs to have some sort of random thing that annoys the game player when they eat dinner. This could be a HouseFly or a Telemarketer or both -- but how do you allow for both with a single function? And how do you ask each different type of object to "do their annoying thing" in the same way?

The key to realize is that both a Telemarketer and HouseFly share a common loosely interpreted behavior even though they are nothing alike in terms of modeling them. So, let's make an interface that both can implement:

interface IPest {
    void BeAnnoying();
}

class HouseFly inherits Insect implements IPest {
    void FlyAroundYourHead(){}
    void LandOnThings(){}

    void BeAnnoying() {
        FlyAroundYourHead();
        LandOnThings();
    }
}

class Telemarketer inherits Person implements IPest {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}

    void BeAnnoying() {
        CallDuringDinner();
        ContinueTalkingWhenYouSayNo();
    }
}

We now have two classes that can each be annoying in their own way. And they do not need to derive from the same base class and share common inherent characteristics -- they simply need to satisfy the contract of IPest -- that contract is simple. You just have to BeAnnoying. In this regard, we can model the following:

class DiningRoom {

    DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

    void ServeDinner() {
        when diningPeople are eating,

        foreach pest in pests
        pest.BeAnnoying();
    }
}

Here we have a dining room that accepts a number of diners and a number of pests -- note the use of the interface. This means that in our little world, a member of the pests array could actually be a Telemarketer object or a HouseFly object.

The ServeDinner method is called when dinner is served and our people in the dining room are supposed to eat. In our little game, that's when our pests do their work -- each pest is instructed to be annoying by way of the IPest interface. In this way, we can easily have both Telemarketers and HouseFlys be annoying in each of their own ways -- we care only that we have something in the DiningRoom object that is a pest, we don't really care what it is and they could have nothing in common with other.

This very contrived pseudo-code example (that dragged on a lot longer than I anticipated) is simply meant to illustrate the kind of thing that finally turned the light on for me in terms of when we might use an interface. I apologize in advance for the silliness of the example, but hope that it helps in your understanding. And, to be sure, the other posted answers you've received here really cover the gamut of the use of interfaces today in design patterns and development methodologies.

The specific example I used to give to students is that they should write

List myList = new ArrayList(); // programming to the List interface

instead of

ArrayList myList = new ArrayList(); // this is bad

These look exactly the same in a short program, but if you go on to use myList 100 times in your program you can start to see a difference. The first declaration ensures that you only call methods on myList that are defined by the List interface (so no ArrayList specific methods). If you've programmed to the interface this way, later on you can decide that you really need

List myList = new TreeList();

and you only have to change your code in that one spot. You already know that the rest of your code doesn't do anything that will be broken by changing the implementation because you programmed to the interface.

The benefits are even more obvious (I think) when you're talking about method parameters and return values. Take this for example:

public ArrayList doSomething(HashMap map);

That method declaration ties you to two concrete implementations (ArrayList and HashMap). As soon as that method is called from other code, any changes to those types probably mean you're going to have to change the calling code as well. It would be better to program to the interfaces.

public List doSomething(Map map);

Now it doesn't matter what kind of List you return, or what kind of Map is passed in as a parameter. Changes that you make inside the doSomething method won't force you to change the calling code.

Programming to an interface is saying, "I need this functionality and I don't care where it comes from."

Consider (in Java), the List interface versus the ArrayList and LinkedList concrete classes. If all I care about is that I have a data structure containing multiple data items that I should access via iteration, I'd pick a List (and that's 99% of the time). If I know that I need constant-time insert/delete from either end of the list, I might pick the LinkedList concrete implementation (or more likely, use the Queue interface). If I know I need random access by index, I'd pick the ArrayList concrete class.

Using interfaces is a key factor in making your code easily testable in addition to removing unnecessary couplings between your classes. By creating an interface that defines the operations on your class, you allow classes that want to use that functionality the ability to use it without depending on your implementing class directly. If later on you decide to change and use a different implementation, you need only change the part of the code where the implementation is instantiated. The rest of the code need not change because it depends on the interface, not the implementing class.

This is very useful in creating unit tests. In the class under test you have it depend on the interface and inject an instance of the interface into the class (or a factory that allows it to build instances of the interface as needed) via the constructor or a property settor. The class uses the provided (or created) interface in its methods. When you go to write your tests, you can mock or fake the interface and provide an interface that responds with data configured in your unit test. You can do this because your class under test deals only with the interface, not your concrete implementation. Any class implementing the interface, including your mock or fake class, will do.

EDIT: Below is a link to an article where Erich Gamma discusses his quote, "Program to an interface, not an implementation."

http://www.artima.com/lejava/articles/designprinciples.html

You should look into Inversion of Control:

In such a scenario, you wouldn't write this:

IInterface classRef = new ObjectWhatever();

You would write something like this:

IInterface classRef = container.Resolve<IInterface>();

This would go into a rule-based setup in the container object, and construct the actual object for you, which could be ObjectWhatever. The important thing is that you could replace this rule with something that used another type of object altogether, and your code would still work.

If we leave IoC off the table, you can write code that knows that it can talk to an object that does something specific, but not which type of object or how it does it.

This would come in handy when passing parameters.

As for your parenthesized question "Also, how could you write a method that takes in an object that implements an Interface? Is that possible?", in C# you would simply use the interface type for the parameter type, like this:

public void DoSomethingToAnObject(IInterface whatever) { ... }

This plugs right into the "talk to an object that does something specific." The method defined above knows what to expect from the object, that it implements everything in IInterface, but it doesn't care which type of object it is, only that it adheres to the contract, which is what an interface is.

For instance, you're probably familiar with calculators and have probably used quite a few in your days, but most of the time they're all different. You, on the other hand, knows how a standard calculator should work, so you're able to use them all, even if you can't use the specific features that each calculator has that none of the other has.

This is the beauty of interfaces. You can write a piece of code, that knows that it will get objects passed to it that it can expect certain behavior from. It doesn't care one hoot what kind of object it is, only that it supports the behavior needed.

Let me give you a concrete example.

We have a custom-built translation system for windows forms. This system loops through controls on a form and translate text in each. The system knows how to handle basic controls, like the-type-of-control-that-has-a-Text-property, and similar basic stuff, but for anything basic, it falls short.

Now, since controls inherit from pre-defined classes that we have no control over, we could do one of three things:

  1. Build support for our translation system to detect specifically which type of control it is working with, and translate the correct bits (maintenance nightmare)
  2. Build support into base classes (impossible, since all the controls inherit from different pre-defined classes)
  3. Add interface support

So we did nr. 3. All our controls implement ILocalizable, which is an interface that gives us one method, the ability to translate "itself" into a container of translation text/rules. As such, the form doesn't need to know which kind of control it has found, only that it implements the specific interface, and knows that there is a method where it can call to localize the control.

It sounds like you understand how interfaces work but are unsure of when to use them and what advantages they offer. Here are a few examples of when an interface would make sense:

// if I want to add search capabilities to my application and support multiple search
// engines such as Google, Yahoo, Live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

then I could create GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider, etc.

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

then create JpegImageLoader, GifImageLoader, PngImageLoader, etc.

Most add-ins and plugin systems work off interfaces.

Another popular use is for the Repository pattern. Say I want to load a list of zip codes from different sources

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

then I could create an XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, etc. For my web applications, I often create XML repositories early on so I can get something up and running before the SQL Database is ready. Once the database is ready I write an SQLRepository to replace the XML version. The rest of my code remains unchanged since it runs solely off of interfaces.

Methods can accept interfaces such as:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}

It makes your code a lot more extensible and easier to maintain when you have sets of similar classes. I am a junior programmer, so I am no expert, but I just finished a project that required something similar.

I work on client side software that talks to a server running a medical device. We are developing a new version of this device that has some new components that the customer must configure at times. There are two types of new components, and they are different, but they are also very similar. Basically, I had to create two config forms, two lists classes, two of everything.

I decided that it would be best to create an abstract base class for each control type that would hold almost all of the real logic, and then derived types to take care of the differences between the two components. However, the base classes would not have been able to perform operations on these components if I had to worry about types all of the time (well, they could have, but there would have been an "if" statement or switch in every method).

I defined a simple interface for these components and all of the base classes talk to this interface. Now when I change something, it pretty much 'just works' everywhere and I have no code duplication.

If you program in Java, JDBC is a good example. JDBC defines a set of interfaces but says nothing about the implementation. Your applications can be written against this set of interfaces. In theory, you pick some JDBC driver and your application would just work. If you discover there's a faster or "better" or cheaper JDBC driver or for whatever reason, you can again in theory re-configure your property file, and without having to make any change in your application, your application would still work.

Programming to Interfaces is awesome, it promotes loose coupling. As @lassevk mentioned, Inversion of Control is a great use of this.

In addition, look into SOLID principals. here is a video series

It goes through a hard coded (strongly coupled example) then looks at interfaces, finally progressing to a IoC/DI tool (NInject)

To add to the existing posts, sometimes coding to interfaces helps on large projects when developers work on separate components simultaneously. All you need is to define interfaces upfront and write code to them while other developers write code to the interface you are implementing.

It is also good for Unit Testing, you can inject your own classes (that meet the requirements of the interface) into a class that depends on it

Imagine you have a product called 'Zebra' that can be extended by plugins. It finds the plugins by searching for DLLs in some directory. It loads all those DLLs and uses reflection to find any classes that implement IZebraPlugin, and then calls the methods of that interface to communicate with the plugins.

This makes it completely independent of any specific plugin class - it doesn't care what the classes are. It only cares that they fulfill the interface specification.

Interfaces are a way of defining points of extensibility like this. Code that talks to an interface is more loosely coupled - in fact it is not coupled at all to any other specific code. It can inter-operate with plugins written years later by people who have never met the original developer.

You could instead use a base class with virtual functions - all plugins would be derived from the base class. But this is much more limiting because a class can only have one base class, whereas it can implement any number of interfaces.

In Java these concrete classes all implement the CharSequence interface:

CharBuffer, String, StringBuffer, StringBuilder

These concrete classes do not have a common parent class other than Object, so there is nothing that relates them, other than the fact they each have something to do with arrays of characters, representing such, or manipulating such. For instance, the characters of String cannot be changed once a String object is instantiated, whereas the characters of StringBuffer or StringBuilder can be edited.

Yet each one of these classes is capable of suitably implementing the CharSequence interface methods:

char charAt(int index)
int length()
CharSequence subSequence(int start, int end)
String toString()

In some cases, Java class library classes that used to accept String have been revised to now accept the CharSequence interface. So if you have an instance of StringBuilder, instead of extracting a String object (which means instantiating a new object instance), it can instead just pass the StringBuilder itself as it implements the CharSequence interface.

The Appendable interface that some classes implement has much the same kind of benefit for any situation where characters can be appended to an instance of the underlying concrete class object instance. All of these concrete classes implement the Appendable interface:

BufferedWriter, CharArrayWriter, CharBuffer, FileWriter, FilterWriter, LogStream, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, StringBuffer, StringBuilder, StringWriter, Writer

So, just to get this right, the advantage of a interface is that I can separate the calling of a method from any particular class. Instead creating a instance of the interface, where the implementation is given from whichever class I choose that implements that interface. Thus allowing me to have many classes, which have similar but slightly different functionality and in some cases (the cases related to the intention of the interface) not care which object it is.

For example, I could have a movement interface. A method which makes something 'move' and any object (Person, Car, Cat) that implements the movement interface could be passed in and told to move. Without the method every knowing the type of class it is.

program to an interface is a term from the GOF book. i would not directly say it has to do with java interface but rather real interfaces. to achieve clean layer separation, you need to create some separation between systems for example: Let's say you had a concrete database you want to use, you would never "program to the database" , instead you would "program to the storage interface". Likewise you would never "program to a Web Service" but rather you would program to a "client interface". this is so you can easily swap things out.

i find these rules help me:

1. we use a java interface when we have multiple types of an object. if i just have single object, i dont see the point. if there are at least two concrete implementations of some idea, then i would use a java interface.

2. if as i stated above, you want to bring decoupling from an external system (storage system) to your own system (local DB) then also use a interface.

notice how there are two ways to consider when to use them.

Previous answers focus on programming to an abstraction for the sake of extensibility and loose coupling. While these are very important points, readability is equally important. Readability allows others (and your future self) to understand the code with minimal effort. This is why readability leverages abstractions.

An abstraction is, by definition, simpler than its implementation. An abstraction omits detail in order to convey the essence or purpose of a thing, but nothing more. Because abstractions are simpler, I can fit a lot more of them in my head at one time, compared to implementations.

As a programmer (in any language) I walk around with a general idea of a List in my head at all times. In particular, a List allows random access, duplicate elements, and maintains order. When I see a declaration like this: List myList = new ArrayList() I think, cool, this is a List that's being used in the (basic) way that I understand; and I don't have to think any more about it.

On the other hand, I do not carry around the specific implementation details of ArrayList in my head. So when I see, ArrayList myList = new ArrayList(). I think, uh-oh, this ArrayList must be used in a way that isn't covered by the List interface. Now I have to track down all the usages of this ArrayList to understand why, because otherwise I won't be able to fully understand this code. It gets even more confusing when I discover that 100% of the usages of this ArrayList do conform to the List interface. Then I'm left wondering... was there some code relying on ArrayList implementation details that got deleted? Was the programmer who instantiated it just incompetent? Is this application locked into that specific implementation in some way at runtime? A way that I don't understand?

I'm now confused and uncertain about this application, and all we're talking about is a simple List. What if this was a complex business object ignoring its interface? Then my knowledge of the business domain is insufficient to understand the purpose of the code.

So even when I need a List strictly within a private method (nothing that would break other applications if it changed, and I could easily find/replace every usage in my IDE) it still benefits readability to program to an abstraction. Because abstractions are simpler than implementation details. You could say that programming to abstractions is one way of adhering to the KISS principle.

Coding to an interface is a philosophy, rather than specific language constructs or design patterns - it instructs you what is the correct order of steps to follow in order to create better software systems (e.g. more resilient, more testable, more scalable, more extendible, and other nice traits).

What it actually means is:

===

Before jumping to implementations and coding (the HOW) - think of the WHAT:

  • What black boxes should make up your system,
  • What is each box' responsibility,
  • What are the ways each "client" (that is, one of those other boxes, 3rd party "boxes", or even humans) should communicate with it (the API of each box).

After you figure the above, go ahead and implement those boxes (the HOW).

Thinking first of what a box' is and what its API, leads the developer to distil the box' responsibility, and to mark for himself and future developers the difference between what is its exposed details ("API") and it's hidden details ("implementation details"), which is a very important differentiation to have.

One immediate and easily noticeable gain is the team can then change and improve implementations without affecting the general architecture. It also makes the system MUCH more testable (it goes well with the TDD approach).

===
Beyond the traits I've mentioned above, you also save A LOT OF TIME going this direction.

Micro Services and DDD, when done right, are great examples of "Coding to an interface", however the concept wins in every pattern from monoliths to "serverless", from BE to FE, from OOP to functional, etc....

I strongly recommend this approach for Software Engineering (and I basically believe it makes total sense in other fields as well).

"Program to interface" means don't provide hard code right the way, meaning your code should be extended without breaking the previous functionality. Just extensions, not editing the previous code.

I strongly believe hard questions should be explained with easy real-world answers. And in the realm of software design, it's very important.

Look at any door in your house, school, church... any building.

Imagine some doors got the perils right-bottom (so you have to bow to interact with the door, which is open or close it),

Or others got just in the top-left (So, some dwarfs, people with disabilities, or Kevin Hart will not find very amusing and usable such doors ).

So design is the keyword, create programs to others humans can develop/use it.

What Interfaces does is to make things easy for other junior/senior developers across colossus projects[1], so everybody knows what are they doing with little help from others so you can work as smooth as possible (in Theory).


[1]: How? By exposing the shape of value. So, you don't need documentation, cause the code itself is self-explanatory (Awesome).


This answer was not meant to be for language-specific instead of concept-driven (After all, humans are creating tools by writing code).

Related