DEV Community

Suhas Chatekar
Suhas Chatekar

Posted on

How do you choose between an interface and abstract class?

I have been asking this question in interviews for some years now. I get to hear a lot of interesting answers from folks. All these answers have helped me make a great addition to my knowledge. If you google this topic you would find a lot of interesting articles. This article on MSDN offers a good discussion on the topic. To summarise the recommendations from there and few other articles I have come across, here are the reasons in favour of abstract classes

  1. Use abstract class if you have a default implementation of some behaviour that child classes do not have to implement
  2. Prefer abstract classes if your contract has a possibility of changing over time. So if you are using an abstract class and need to add a new method to your abstract class, you can happily add that without breaking any code using that class. The same is not true for interfaces.

And these are the reasons in favour of interfaces

  1. Since multiple inheritance is not supported in C#, you cannot inherit your class from two abstract classes. An interface is your only option in such situations.
  2. If there is no default or common behaviour among all the classes that are inheriting from abstract class then interface may be a better choice.

I personally do not believe that these give a complete picture.

What is wrong with this reasoning?

First, above recommendations are mostly around syntax a particular language supports and not around semantics (e.g. use interfaces if you need multiple inheritance). By semantics I mean, what definition of an interface fundamentally differentiates it from an abstract class?
Second, I feel the above criteria are too futuristic. By that I mean, they all depend on you knowing how your design is going to take shape in future. At times, I may have some idea of how my design is going to take shape in future but most of the times I do not have enough clarity to know in advance

  1. Whether I am going to need to inherit from multiple abstract classes or not
  2. Whether there is going to be a default implementation of some contract or not
  3. Whether I would add a new method to a contract or define a new contract entirely in order to implement a change

So, if you do not know which way your software is going to go, there is no way you can base your decision of interface or abstract class on these reasons.

So how do we decide?

Lately, I have been using below heuristic to determine when to use interfaces/abstract classes and I feel quite excited about it as it works most of the time.

Interfaces represent capabilities and abstract classes represent type

in other words

Implementing interfaces represents can-do relationship and inheriting from (abstract) class represents an is-a relationship

To elaborate this point, let's consider following two classes

public class Camera 
{ 
  public void Shoot() 
  { 
    //Take a picture here 
  } 
} 

public class Gun 
{ 
  public void Shoot() 
  { 
    //Hit the target 
  } 
}
Enter fullscreen mode Exit fullscreen mode

Both Camera and Gun can Shoot, that is their capability. But they are both not the same type of things, they are completely different. So an interface like below would make more sense here

public interface IShootable 
{ 
  void Shoot(); 
} 

public class Camera : IShootable 
{ 
  public void Shoot() 
  { 
    //Take a picture here 
  } 
} 

public class Gun : IShootable 
{ 
  public void Shoot() 
  { 
    //Hit the target 
  } 
}

Enter fullscreen mode Exit fullscreen mode

If you have learned OO programming the same way I did, then you would remember the classic shape example as below

public abstract class Shape 
{ 
  void Draw(); 
} 

public class Rectangle : Shape 
{ 
  public void Draw() 
  { 
    //Draw a rectangle here 
  } 
} 

public class Circle : Shape 
{ 
  public void Draw() 
  { 
    //Draw a circle here 
  } 
}

Enter fullscreen mode Exit fullscreen mode

Rectangle and Circle inheriting from Shape makes perfect sense here because Rectangle/Circle are a type of Shape.

In closing

As your software grows and new features start pouring in, old features keep changing, you would hit a point where you would say to yourself “Oh God, I should not have used an abstract class here”. Instead of trying to predict feature about who will reuse which code, focus on determining whether it is a capability that you are abstracting away or a common type. If you find that line of thinking difficult, then work out if it is a can-do relationship that you are trying to model or an is-a relationship.

Top comments (16)

Collapse
 
joelbennett profile image
Joel Bennett

Having taken a bit of a break from C# for a while, I think it has changed my perspective. Working in Python has got me thinking more in terms of functional programming. I'd now see this as the following:

  • Do you need state and behaviour? Use an abstract class.
  • Do you only need behaviour? Use an interface.
Collapse
 
dubyabrian profile image
W. Brian Gourlie

My take: An interface is a contract, a class is a concrete representation of something, and an abstract class is a unecessary and limiting combination of the two—An additional language construct with a very specific use that can be accomplished naturally other ways.

Abstract classes are the bane of my existence in an inversion-of-control and TDD world.

Collapse
 
lovis profile image
Lovis • Edited

👍 "How do you choose between an interface and an abstract class?" You use an interface.

Collapse
 
ghost profile image
Ghost

I'd generally recommend interfaces if you want to publish your codebase as library, as your users are not forced to abide your inheritance.

In this scenario, it's advisable to publish an interface and provide a default implememtation (similar to IEnumerable and everything in System.Collections)

Collapse
 
mathieuhalley profile image
Mathieu Halley

Practically, one use I've found for interfaces is to tag classes. The the interface isn't needed by the program, but having it there helps you to understand the purpose of a given class e.g.: "class UIHandler : IClickHandler, IDragHandler"

Collapse
 
suhas_chatekar profile image
Suhas Chatekar

Nice trick.

Collapse
 
pedromanoel profile image
Pedro Manoel Fabiano Alves Evangelista

Really great article, thanks!

I like that you showed a simple guideline for reasoning about this problem, and I think it works great for lots of cases. However, there are cases where it is not so easy for me to see the distinction.

For instance, I would argue that the interfaces Map, List and Set from Java represents an "is-a" relationship, and not a "can-do". Other interfaces such as Cloneable and Serializable are clearly representations of "can-do" relationships (suffix "able").

I think interfaces can be used both for "is-a" and "can-do" relationships, while abstract classes can only be used for "is-a" relationships because of the semantics of inheritance.

What if we think along the line of Interfaces for contracts and Abstract classes for partial implementations? Like how the Java API have abstract classes such as AbstractMap and AbstractList for Map and List, respectivelly.

Collapse
 
unitycoach profile image
Unity Coach

I work in the game industry and actually happen to use both interfaces and abstract together. In some cases, abstract base classes can implement interfaces, which makes it pretty handy later not to have to know what such or such class can do. You simply add different "can-do" to different levels of "is-a".

Collapse
 
suhas_chatekar profile image
Suhas Chatekar

And that makes perfect sense. You have an interface to represent the "can-do" relationship and an abstract class where you can stash any common implementation.

Collapse
 
nonsobiose profile image
Nonso Biose

Thank you Suhas, you have just helped me understand the difference btw those concepts. Now I can feel like a pro when asked the tricky question

Collapse
 
bgadrian profile image
Adrian B.G. • Edited

Speaking of OOP and the basic Shape example, here is a some good lecture from Uncle Bob about why inheritance is bad sometimes (or always)

Bob Martin SOLID

PS: I suggest watching the entire playlist, you will learn a lot. But do not take his teachings as an absolute truth, soak them using your own filters and knowledge and seek for pro/cons in every scenario.

From my experience it's a bad way of thinking replicating real life models into code, above a point. When you have a choice example between an optimization and keeping the hierarchy same as in real life choose the optimization. I think this is the main cause of overusing inheritance.

Also there are tons of materials on why you should prefer composition over inheritance.

I love the way Go implemented interfaces (passive implicit implementations) & classes (not at all). They fixed many problems for big projects & library imports.

Collapse
 
suhas_chatekar profile image
Suhas Chatekar

Absolutely - composition over inheritance at any time. Having said that, abstract classes have a place in any OO language and I have seen people confusing between abstract classes and interfaces.

Collapse
 
gwunhar profile image
Mardoch

Very helpful piece. It's something I always ended up searching for before going one way or another. This is probably the most cogent explanation of the concept that I've read.

Collapse
 
dnltsk profile image
Daniel Teske

Is-a/has-a differenciation is reasonable. However in your Shape example I would use an IDrawable.
U need abstract classes e.g. when the template pattern needs to be implemented.
Cheers

Collapse
 
suhas_chatekar profile image
Suhas Chatekar

Shape example is just an "example" as it is most commonly understood by everyone. I think it is "Hello World" of inheritance.

Collapse
 
elcotu profile image
Daniel Coturel

Hi Suhas,
Another conceptualization that helped me a lot to understand when and how to use an abstract class is the design pattern "Layer Supertype" by Martin Fowler.
Saludos,