The Difference Between An Interface and an Abstract Class
I've had a couple developers ask if they should use an interface or an abstract class. Today, I'll talk about the differences between the two and which one you should use based on your needs.
Do you know the difference between an interface and an abstract class?
This question gets asked a number of times during interviews and, to be honest, some developers cannot answer it correctly.
If you are looking for a developer who's worth their salt, they would be able to answer this.
"What's the difference between an Interface and an Abstract Class?"
Let's dig into it.
Interfaces
Interfaces define a contract between classes. Think of an interface as the 40,000-foot view of a class. They include the method and property signatures with no details. It gives you a first pass of designing your class without digging into the details of what it's supposed to do.
Here is the characteristics of an Interface:
No implementation details
Interfaces just tell the overall story of the class and does not contain any meat, or implementation details.
For example,
public interface IUser { int Id { get; set; } string UserName { get; set; } DateTime LastLogin { get; set; } string FirstName { get; set; } string LastName { get; set; } string GetFullName(); }
The IUser Interface shows we can use five properties and one method called GetFullName(). Currently, we don't have any classes that IUser can attach to at this time.
We don't even have scope attached to any properties (i.e. public, protected, or private) because interfaces don't use them.
Contract of methods and properties
As mentioned above, interfaces can only use methods and properties. When we attach the Interface to a concrete class, it checks to see if all of the properties and methods are within that class.
However, you cannot add implementation details to an interface, only to a concrete class like so:
public class User : IUser { public int Id { get; set; } public string UserName { get; set; } public DateTime LastLogin { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string GetFullName() { return String.Format("{0} {1}", FirstName, LastName); } }
Provides a decoupling of classes
When you inherit from a class to create another class, that is called tightly coupling. When you attach interfaces to concrete classes, this is considered loosely coupling your classes.
If you don't have a lot of implementation details, I would recommend using interfaces.
It's much easier to refactor interfaces than it is to refactor concrete classes.
I guess it depends on the context of the refactoring.
Simulate multiple inheritance
You can add any number of interfaces to a class. ANY number.
Look at this example.
If we have another user who is a staff member, we can create a new type of User using interfaces.
public interface IStaffMember: IUser, IStudent { string Title { get; set; } }
You mean a Staff Member can be a User AND a Student? Yes!
Now, if we use that interface on a plain object, we get all of the parameters required for a User AND a Staff Member.
public class User : IStaffMember { public int Id { get; set; } // Id (Primary key) public string UserName { get; set; } // UserName public DateTime LastLogin { get; set; } // LastLogin public string FirstName { get; set; } // FirstName public string LastName { get; set; } // LastName public string Title { get; set; }
public string GetFullName() { return String.Format("{0} {1}", FirstName, LastName); } }
Notice we didn't modify any concrete classes. We strictly added another property to it through the interface.
Since we added that new property, every class using the IStaffMember will complain because the new property (or methods) doesn't provide any implementation details.
Abstract Classes
Now if we shift our focus to Abstract classes, an abstract class provides a useful base class with implementation details and all of the trimmings. The one issue regarding abstract classes is that you can't instantiate abstract classes. You need a class to inherit from it and then you can instantiate it.
Here are the characteristics of an abstract class:
Cannot be instantiated directly
What the heck does that mean?
Let's use a car example.
We want to create a car. The base car has wheels and the name of the manufacturer.
public abstract class Car { public int Wheels { get; set; } public string Manufacturer { get; set; } }
Now, we can't instantiate the Car class directly because it's an abstract class, but we can inherit from it.
var newCar = new Car();
This will give you an error, but if you inherit from the Car class,
public class Ford : Car { } public class Dodge : Car { } public class Chevrolet : Car { }
This will give you your separate car lines to implement different details for each car.
Implementation details
As I mentioned above, your abstract class can have implementation details to specific to one class or to all classes.
If all of your cars have tires (duh!), then you would add a property to the Car abstract class so every car inheriting that has four wheels and tires.
If you want to place specific parts on specific cars, you can just add that to your Dodge or Ford class.
The whole idea for abstract classes is that you try to find the common denominators in all of the objects and place them into your abstract class.
If a property or method becomes way too specific, place it into the appropriate class (i.e. Dodge, Ford, Chevrolet).
Remember, if it's general, place it into an abstract class. If it's specific, place it in your inherited class.
Conclusion
Throughout my career, I've experienced a number of developers during an interview (even 10+ year developers) who couldn't tell me the difference between the two.
An interface and abstract class are fundamental concepts but extremely important to understand (especially during an interview). ;-)
Which one is better? Again, it depends on your use, but here are some tips:
- Mocking frameworks in unit tests depend heavily on interfaces to create mocked objects.
- Interfaces provide loosely coupled applications which makes your development a lot easier to replace code or components.
- If you have a large class hierarchy with a ton of implementation details, use an abstract class.
- Abstract classes are great for Strategy Patterns.
Hopefully, I didn't confuse anyone in my explanations of each term.
Did I miss one characteristic that you didn't see in the list? Post your comment below and help me out.