Software Development

When to use interfaces instead of classes

An interface defines common functionality across unrelated classes. Here's an overview of five of the most common reasons to use interfaces and when to avoid them.

A few years ago, I started seeing developers use interfaces instead of classes in a lot of places. This is a good thing, because it has taken a long time for many developers to really understand object-oriented programming (OOP), and a lot of programmers (myself included) were disguising imperative code with just enough OOP to make things compile. Unfortunately, in many of these scenarios, the technique was being abused or overly used.

Here's a look at some of the situations where it makes sense to use interfaces instead of classes, and where is does not. But first, I'll explain what an interface is at the simplest level.

What exactly is an interface?

An interface defines common functionality across unrelated classes. For example, all sorts of classes that look nothing like each other may have the need to safely get rid of the resources they use.

The IDisposable interface (the name for it in .NET) defines a Dispose() method, which classes then implement. A programmer using those classes knows that, if a class implements the IDisposable interface, the Dispose() method is used to safely release resources.

An interface is a guarantee that certain functionality will work in a standardized way. When properly fashioned, an interface encompasses only the bare minimum for the defined functionality. IEnumerable (which is used to iterate over sequences, lists, sets, etc.), for example, does not provide for a Count property, because it is not concerned with "how many?" it is only worried about "the next one in the sequence."

APIs

I believe you get the most advantage from using interfaces as often as possible when you are writing an API. In an API, you want your code to be as loosely coupled as possible in terms of input and output; after all, you have no control over what the consuming application will need.

There may be a time when it is tempting to work with a List<T> within a piece of code, and then just return the List<T>, for example. The consumers of the API usually do not need all of the functionality of List<T>, and you can output IEnumerable<T> instead. This way, if the consumer wants a List<T>, they can have it, or they can have an array of T, or whatever else they might need. By using the common denominator interfaces in your API, you free the consumers from being forced to use or convert to/from your class of choice.

Tightly coupled code

In the fantasy land of Computer Science courses and the blogosphere, developers never write tightly coupled code. In reality, tightly coupled code is a fact of life for the average developer.

You aren't going to make an abstract class and implement the Factory pattern to "future proof" yourself against changes when writing a three line of code class will give you a strong type to shuffle data around. Likewise, coding to interfaces is impractical in many situations; a key sign of this is when you find yourself writing classes that look a lot like structures.

If the only or the best way to get something done is to tightly couple code, then trying to abstract some kind of common functionality into an interface is either doomed to fail or merely more effort than it is worth.

Future proofing

Working with interfaces can give you a measure of future proofing when you are on the consuming end of things. If you are using a library that outputs interface instances instead of classes, not recasting those instances as classes can protect you from changes down the road. Along the same lines, if you only need a certain subset of functionality contained within an interface, working against that interface is better than working against the class.

Go back six or seven years before we had generic types -- if you had coded everything to take arrays or Hashtables instead of IEnumerable or ICollection, then if the library ever changed to use List<T> or Dictionary<T>, you would have a long road ahead of you to convert over.

Code clarity

Coding with interfaces can improve code readability. How? Because there are fewer "moving parts" for the reader to keep in mind. When you work with an interface, it is more clear what your intentions are and what the capabilities will be. Code is more self-documenting when working with interfaces for this reason.

Sometimes an interface just won't do

Some folks take the use of interfaces to an unworkable extreme. Avoid this at all costs. There will be times when you simply cannot boil down the essence of a variable or a method parameter (or whatever) to an interface. In fact, this is more likely than not. Don't try to force the issue; it's better to just use a class and move on with your life than to try to make things work with an interface.

I would love to hear about your experiences with interfaces. Please share them in the related discussion.

J.Ja

Disclosure of Justin's industry affiliations: Justin James has a contract with Spiceworks to write product buying guides; he has a contract with OpenAmplify, which is owned by Hapax, to write a series of blogs, tutorials, and articles; and he has a contract with OutSystems to write articles, sample code, etc.

---------------------------------------------------------------------------------------

Get weekly development tips in your inbox Keep your developer skills sharp by signing up for TechRepublic's free Web Developer newsletter, delivered each Tuesday. Automatically subscribe today!

About

Justin James is the Lead Architect for Conigent.

48 comments
bergenfx
bergenfx

How much does the implementation language affect how some of you (participants in this thread) think about software problems? Do you model with interfaces even if the language does not support them? Do you model using the object model even if it is not an OO language? If it is OO does everything look like an object, but if everything is SNOBOL everything looks like a string. I guess I am asking how much of our thinking is determined by implementation language constructs.

lishchuk
lishchuk

Justin wrote: "An interface defines common functionality across unrelated classes" To be correct, it should be: "An interface declares common interface i.e. it just declare an API". In other words, interface has nothing to do with any functionality (implementation) , all functionality is up to implementation classes".

jconigliaro
jconigliaro

Think of an interface as more of a contract than anything else. When a class implements an interface it is telling the outside world that it will "look like bla" It really doesn't say anything about how something will or won't work, just that it's interface will have a certain signature. I question making statements like interfaces are good for dealing with APIs, reducing coupling or for future proofing your code. There isn't anything inherent in the concept of an interface that makes it better or worse for solving these types of problems. In each of those instances the use of an interface is just part of an overall design (or design pattern) used to address a specific problem.

Tony Hopkinson
Tony Hopkinson

misused, though they are no different to any other technique in that. My tip in terms of estimating suitability of teh construct is very simple. Look for explicit casts, the more you have, the more you've gone wrong. I do tend to use them to avoid coupling, particularly deep inheritance models which I loathe, having been lumbered with trying to change the damn things as requirements evolve.

bklau2006
bklau2006

I have a developer at previous job that was infatuated with interfaces. So he implements "I-this" or "I-that". The problem is I see no or little possibility that his "I-this" or "I-that" interfaces would be implemented by other classes besides this sole incidental use. My rule of thumb is that if you are not looking for substituting alternative implementation such that client("consumer") code are written generically to use the interface, don't do it. Also, the rage of dependency injection(DI) may have heightened to novices and the alike that need to code to interfaces. Like someone says, "Too much of a good thing..."

robert
robert

Hear hear! Remember there is a continuum between imperative programming, object-oriented programming (with classes, methods, etc) and component-oriented programming (with components, interfaces, etc). Use what best fits the situation.

Saurondor
Saurondor

I'd like to see interfaces as the minimum set of behaviors that define something. Thus if a class implements an interface it can be said that it behaves as the thing defined by the interface. Working on this I'd like to focus the view of interfaces as a way to define functionality that is later implemented in a class. Rather than view interfaces as a way to "generalize", achieve decoupling, class swapping and other "project management benefits". Look at them as a way to simplify things rather than look ahead. Since objects can implement any amount of interfaces they can be set to behave as something they inherently are not. Take for example a JFrame or any other GUI component that I need to notify of a change. I can easily declare the CommDataListener and have all the windows that need notification implement it. Updating all windows is then as easy as adding the notifiable object to a list of CommDataListeners and iterate over it when an event happens. Each window will in turn take the appropriate (hopefully thread safe!) steps to update itself. Another example is when you have different objects that have to behave differently along their life cycle. A clear example that comes to mind is data acquisition. In which you have a data read step, a data process step and finally a data storage step. I can have different sources of a data record: TCP/IP socket stream, usb/serial port, flat text or spreadsheet file etc, and one way to store it. Data can have different origins and will be of different originating class types, but by implementing a common interface I can guarantee I'll be able to process and store it regardless of the source. I might never update this down the road or publish the api, but using interfaces rather than one "uber super class" simplifies my own code. It also helps to work around cases in which I can't extend from a class so I use a wrapper class that implements the interface. So instead of looking at interfaces as a way to generalize everything and come up with the solution to all my programming woes I like to look at interfaces as a way to simplify things. To declare the bare bones functionality to do something and then have classes implement interfaces as the need to do more "somethings" arises. I believe a great deal of frustration emerges when interfaces are utilized for the sake of using them and they become "synonyms" of the class in the odd chance that in the future we'll need to swap implementations. Using interfaces is a good practice if the objects you'll be using have different hierarchies. Thus making it impossible to have one common superclass without multiple inheritance. Examples of this is the data acquisition I just mentioned and DAOs. In such a case you might already be extending some class to implement some base data access functionality. Its also a good practice if you can't or it doesn't make sense to create one top abstract class that holds such functionality. As is the case of the window notification I mentioned before where I can't modify JComponent or JWindow to add the required abstract update methods. Using interfaces is also valuable and required when you use webservices. So even if you only use one implementation, you never change it and it belongs to its very own private hierarchy, you will still need to code to an interface. Because your client code is actually using a proxy class to your real implementation.

kevin.cline
kevin.cline

Developers in 21st Century languages like Groovy, Ruby, or Python don't face this problem.

mattohare
mattohare

But, the language has a massive affect on how easy it is. Inheritance by delegation in VB6 is a good example of this. To 'inherit' we would create a variable in the class that instantiated the parent object. Then we'd write wrappers for each method or property that we wanted to 'inherit'. I got some shocks when I got to VB.Net, inherited properly, and had more methods than I wanted.

Tony Hopkinson
Tony Hopkinson

even when there was no direct support. Interfaces, I feel are a bit too close to an implementation detail for modelling purposes. You can fall too easily into the trap of over or misuse.

bergenfx
bergenfx

for everybody, or at least one all could agree on

Tony Hopkinson
Tony Hopkinson

Interface ISort { void Sort(); } It doesn't say alpha order, merge or bubble algorithm. Its say the class that implements it has some default order.

mattohare
mattohare

Well, as Justin said, bad interfaces (and bad implementations of them) don't have to do anything of the sort. I think the focus here is what an interface does, when developers use them right. Implement IEnumerable and a class will support the ability the ability to cycle through the objects in a certain way. Anything else is not related to the interface. And, if you can't cycle through the objects in the certain way, then the class does not implement the interface, regardless of what code is there to make the compiler compile without error or warning.

Tony Hopkinson
Tony Hopkinson

An Interface is an explicit definition of the contract, it's enforced by a decent compiler (as long as you don;t go into exlicit cast mode). The real world problem is that you are more likely to need to change the contract than the implementation.... There's always a point in a design where you can get so abstract your implementation does nothing, all scaffolding no building as it were. Even if you get it right, goal posts move and your super design will become cumbersome. Name of the game, change is a given.

Justin James
Justin James

"I question making statements like interfaces are good for dealing with APIs, reducing coupling or for future proofing your code. There isn't anything inherent in the concept of an interface that makes it better or worse for solving these types of problems." While it is true that the technical architecture of an interface does not prevent someone from making bad decisions, if you write an interface in line with the spirit of an interface (like only including the "common denominator" functionality) you absolutely get these advantages. It's kind of like how a car does not guarantee that you will get places faster than riding a bike, because the car driver can always choose to drive 2 miles and hour. J.Ja

mattohare
mattohare

There are some languages that do not allow for multiple inheritance. A way that the language users would 'work around' this is to use interfaces for the additional parent classes. To that end, some languages allow one to put methods and properties in the interfaces. It's a world gone mad when we get to that point.

jvr1967
jvr1967

Nobody said anything about this being a problem. I think the discussion was more about making the best use of 'interfaces'. They are a useful construct which overcome the problems caused by multiple inheritance. Interfaces are not a problem they are a solution. You're attempting to hijack this discussion with a contrived opinion about Groovy, Ruby or Python. In future it would be better if you could be more constructive.

hobbes
hobbes

> Developers in 21st Century languages > like Groovy, Ruby, or Python don't > face this problem. Honestly, this reply looks like a troll. Please provide more detail.

Tony Hopkinson
Tony Hopkinson

when I went (forced at gun point) from Delphi 6 to VB6. Lots of muttering and swearing, f'ing 'orrible.

Saurondor
Saurondor

I believe you just mentioned a key reason to use interfaces rather than classes. "The real world problem is that you are more likely to need to change the contract than the implementation" If your contracts are changing fast it is best to contain them in the interface definition rather than the class definition. That way a contract change can be contained. If you implement a contract through a class definition rather than an implementation then only that class and its descendants will be able to fulfill the contract (without multiple inheritance). If another class is then needed to satisfy the same contract then there is trouble. We can think of classes as DNA and interfaces as RNA. Through the usage of RNA organisms with different DNA can synthesize similar proteins.

Tony Hopkinson
Tony Hopkinson

mind you I've never done a lot in languages that allowed it e.g. C++ Delphi or C#s multiple inheritance through interfaces is something I have used but even then I don't use it for a laugh. The model I loathe is deep inheritance because you never read the chapter on interfaces or multiple inheritance. 18 levels deep, tramp coupled, breathe near it and everything just keels over and dies. Take step one of inheritance (choose the correct ancestor) and throw it in the bin. Re-use gone mad usually.

Tony Hopkinson
Tony Hopkinson

C and later Fortran under VMS. Pascal I'd done was UCSD and Turbo (5 I think). Picked it over VB. It was object oriented not object based. No VBRun.dll The IDE was light years ahead. Got lumbered with doing VB6 in 2003 (ish), going back to Fortran was easier. Probably my biggest stumbling block was the garbage collector, well that and the fact it was shite. Coming from a self managed environment to one where it did things, oh the silly boy forgot to create ths I'll do it for him, was a f'ing nightmare. I learnt that eventually, but the broken syntax and semantics and loose as dynamic typing did me in. Variants, arrrgh. I'm just glad Bill stole Anders from Borland for C#, though i miss virtual static a lot...

mattohare
mattohare

Turbo Pascal was such a let down after I learnt VMS/VAX Pascal that the Delfi adverts went to the bin before I left the post office. (I had a post office box in those days.) AccessBasic thru to VB6 were my progress to OOP.

jimcakalic
jimcakalic

Interface Segregation Principle, anyone?

Tony Hopkinson
Tony Hopkinson

I have n't got a problem with using interface, I just don't like the one size fits all generalisation that they are always the best choice. Us guys who think about design might as well hang up our keyboards and leave it to the cookie cutters, if we go down that route.

Saurondor
Saurondor

Try finding a place for that! ;) Oh and what about aspect oriented programming LOL!

hobbes
hobbes

rRNA = Compilers? Non-coding DNA aka introns = Commented out legacy code? ... I'll have to get back to you on the methylation.

seanferd
seanferd

Just kidding. I can sort of buy into this, assuming that "DNA is like an abstract base class" refers to all of the DNA (in a genome or in a single organism) provides for exactly one single class. Then I can sort of wrap my head around mRNA being an interface, assuming that an interface is an exact duplicate of some coding segment of the single abstract class. tRNA being the metaphor for a class, then, leaves me highly confused. I'll have to ignore rRNA, non-coding DNA/RNA (aside from t, including various regulating types of RNA). I'll also have to assume that this is entirely based on eukaryotic nuclear processes, which does seem to have been indicated.

seanferd
seanferd

I absolutely love comment threads like this. Actually, you could probably use something of a nucleic acid analogy, you would just have to restate it and note where the analogy does not hold. Specifying which type of RNA you are referring to helps as well, so that clarified a bit for me, I think. All that aside, I really do find your programming comments enlightening. edit: Just to be clear, this is the bit that got me. It wasn't the initial metaphor. "Through the usage of RNA organisms with different DNA can synthesize similar proteins." The DNA would have to already code for the similar proteins, RNA just does all the work. It cannot build anything that the DNA does not code for.

Saurondor
Saurondor

Even if there is never going to be more than one single implementation of an interface it makes sense to use interfaces if there are very distinct sets of "roles" in one class. Here's an example. Maybe not the best, but I hope it gets the idea through. Say I want to send an email to everyone on an spreadsheet. I can create a class that has all the mechanisms to handle the loading of data from the spreadsheet and all the mechanisms to create the email content. Lets call it MyUberClass. Then my application can call the myAppInstance.loadData(MyUberClass mailout) to load the information into mailout and then call myAppInstance.sendmails(MyUberClass mailout) to have send the email through my app's preconfigured mail sender. There will only be one implementation of MyUberClass, but the methods used inside loadData are so different from those to send mail that it makes sense to create two interfaces and have MyUberClass implement both. If the ultimate goal was to allow for multiple implementations of MyUberClass we could do that simply by declaring it abstract. By having MyUberClass implement the interfaces SpreadSheetLoader and EmailSender I can now call myAppInstance.loadData(SpreadSheetLoader mailout) and myAppInstance.sendmails(EmailSender mailout). It makes the code a lot more readable and easier to maintain if you do it this way. You can look at the class and see what interfaces it implements, what each interface does etc. Heck even for autocomplete it makes sense to do this as only the interface methods will be visible instead of the whole class methods.

Tony Hopkinson
Tony Hopkinson

one class hierarchy implementing the lot though , if it's likely different implementations are required, then interfaces should be the tool of choice. They can just end up being scaffolding though.

Saurondor
Saurondor

Hey I think you're on to something. CS students should take a semester or two of cellular biology. Similarities are greater than I thought originally and aren't we moving to organic processors ? :) Maybe some day we'll be able to write our nanobot programs with DNA.

Saurondor
Saurondor

I find it a lot easier to think about the bare minimums a certain method needs from its parameters to do its job and from that create an interface that will be later implement by a class than to create an interface based on the possible future needs of a class. So for example if I need to send and email the method that sends it out needs the message body and an attachment. So the parameters can be an interface to provide mailBody() and mailAttachment() as well as string objects for to, from and subject. Then I create the class that actually implements the mailBody and mailAttachment methods. It can create said content by some static string in it, by getting them from a database, by using some template mechanism and what not. To work the other way around is a lot more complex/confusing in my opinion. To create a class that creates a message body and attachment form two templates and then having to figure out what's the best possible interface for future use. Mhhhh. You end up with many abstractions and ideas that could work, but rarely fit and require a lot of retooling. Regarding the metaphor I was thinking on the lines of messenger RNA. It's not meant to be a chemical representation of a program. But rather exemplify how a subset of the class is used to perform a certain function just like a set of genes instead of the whole DNA strand is needed. When you send a class of to do a job through its interface declaration the only methods that can be called upon are the ones published in the interface. You send the gene instead of the whole DNA so to speak. Thus I prefer to work from my protein needs that define my RNA needs that define my genes that define the basics of my DNA class. Rather than lump a lot of genes into an uber DNA class and then try crank out the right proteins. I believe that one of Justin's main concerns as well as others here is the excessive usage of interfaces. To the point that there is an interface for every class. You know, just in case we change the implementation down the road. There are cases were we only need the class without any interface declaration, cases in which the class is the interface (only the methods in the interface exist in the class), cases in which the interface methods are subset of the class methods and cases in which a class implements many interfaces. I think the DNA/RNA example holds very well in the more complex and interesting cases in which the interfaces is a subset of the class methods or the class has many interfaces. But if you still think the RNA/DNA example is off then think about genes and traits. I don't believe interfaces are here to make interchangeable clones out of your code and clases, but rather to define very clear distinctive traits that your class must have. Thus two very different classes can still hold the same distinctive traits. Take the following example. Unit testing a servlet (or a controller in the more modern MVC frameworks). I can send an HttpServletRequest and HttpServletResponse to the controller. I can test the controller by actually setting up the application and feeding it real world container provided http servlet requests and responses or setup a test environment and feed it MockHttpServletRequest and MockHttpServletResponse. Both mock classes implement the HttpSerlvetRequest and HttpServletResponse, but entirely different from those provided by the webserver/container. They're like different organisms with different DNA (gene/traits) that can still do the same exact thing (share one trait). This is another example of interface usage I believe I hadn't come up with that has nothing to do with APIs or down the road upgrades. Another example could be input streams. We can get data through an input stream from a file in a buffered or unbuffered way, it can be from a byte array or a string that came from a database records. We might need to read its contents only once or many times. But the one thing that matters is the minimum set of things input streams need to do to be used as input streams. Regardless of their origins. To sum it up. It is handy to use interfaces to build classes out of "traits" rather than build a class and then try to find out the "traits" others might find interesting in your class. By using interfaces your quick changes are confined to that "trait". Thus preventing possibly hazardous "mutations" to the organism (class).

hobbes
hobbes

I'm sure that what Saurondor meant to say was that interfaces are like RNA, classes are like tRNA, proteins are object instances, DNA is like an abstract base class, histones are like private members, and proxy objects are like the nuclear envelope. Anyone with degrees in cellular biology and computer science will know exactly what I'm talking about. Once you understand that, knowing when to use an interface is a breeze!

seanferd
seanferd

Your metaphor is deeply flawed. It is in the realm of "not even wrong". Best to choose another. Your explanation, however, is very clear. It makes sense to me, but I am not well qualified to make a real judgment on it. As long as any factual claims are correct, and I have no reason to doubt that they are, I do believe I have learned something.

Tony Hopkinson
Tony Hopkinson

value of the PreviousLocation property? Or a member of an enumerated type indicating a relative velocity.. The title of an item in your first CD Catalog application..

bergenfx
bergenfx

lawn mower engine would handle rocket fuel. But there are members of celestial species that do that. Oh, and Tony, same here, but best of Class.

santeewelding
santeewelding

The architecture, morphology, and taxonomy of code handle, "bat out of hell"?

Tony Hopkinson
Tony Hopkinson

then I would have made it an instance of jet engine... :D

Tony Hopkinson
Tony Hopkinson

irate production operatives losing 20% of their pay taught me that lesson. I often wish I could send Big Fred round to see a one or three people who's code I had to unf**k. He cured me of it most emphatically.

bergenfx
bergenfx

to discover that cleverness was not intelligence. Most often, it seems to be a substitute.

bergenfx
bergenfx

meet entendre deux. You two have fun now. More like "is" ... at least, when lucky. Great imagination

Tony Hopkinson
Tony Hopkinson

and naming collisions which I can easily see being a total nightmare. Interfaces address them. I'm sure there are times when MI would be more descriptive, but it's got to be few and far between. The real thing though is the more clever a concept is, the more stupidly clever some people get in applyng it. Plane buzzes, bee flaps and your bat has a jet engine.... Even more likely in something like C++ with it's somewhat relaxed attitude to typing...

bergenfx
bergenfx

I said to myself, "I don't want to get into a discussion about multiple inheritance. It doesn't really excite me, and I don't have much to say." But out there pressure washing everything that does not move, I am thinking about it ... to distraction. So, maybe if I write something, I can think of more pleasant things while I start pressure washing things that do move, (here kitty-kitty). I never had much use for it. In fact, I don't think I ever did or found a need for it. Well, what about mammals who fly? I suppose you could say that you need to abstract out the flying part from the birds and then bats can multiply inherit from Rodent and AbstractFlyingStuff. If that's the issue, then I would rather just use a hasA relation rather than a isA relation. For me, the devil is in the denotational semantics of multiple inheritance. With MI, now I have to keep track of which swoopDown method from what class is getting fired, who is getting overriden, which class's altitude attribute is getting used ... you can tell that I am already confused. It's not that I am lazy, (I know you all can give me a simple explanation of how language B implements MI), but I just want to be sure that I am getting useful power for the additional complexity.

Tony Hopkinson
Tony Hopkinson

concepts. Sheep inherits from FarmyeardAnimal and overides DoNoise to go Baah. So therefore tractor inherits from FarmyardAnimal to go Brmmmm! Obvious really when you think about it..... :( Cookie cutter's guide to architecture.

mattohare
mattohare

Inheritance is to add functionality from the general to the specific. (Such as Web page, then article or form, then type of content on articles.) Interface, pure and simple, is a shared functionality. (The example above, one might apply an interface for applying styles and another for filling in captions. Trivial examples where other technologies would work better.) The problem comes when a language does not support multiple inheritance. So, it allows methods, variables and constants to be added to interfaces.

Editor's Picks