Interface vs Abstract Class
Part of the Object Oriented Programming section of Coddy's C# journey — lesson 26 of 70.
Both interfaces and abstract classes let you define contracts that other classes must follow, but they serve different purposes and have distinct capabilities.
An interface defines what a class must do, without any implementation. It's a pure contract:
public interface IFlyable
{
void Fly();
}
public class Bird : IFlyable
{
public void Fly()
{
Console.WriteLine("Flapping wings");
}
}An abstract class can provide both a contract and shared implementation. It's a partial blueprint:
public abstract class Vehicle
{
public string Brand { get; set; }
public void StartEngine()
{
Console.WriteLine("Engine started");
}
public abstract void Drive(); // Must be implemented
}
public class Car : Vehicle
{
public override void Drive()
{
Console.WriteLine("Driving on roads");
}
}The key differences come down to inheritance rules and purpose.
A class can implement multiple interfaces but inherit from only one abstract class.
Use an interface when unrelated classes need to share behavior (like IFlyable for birds and airplanes). Use an abstract class when related classes share common code and state (like vehicles sharing an engine start mechanism).
Abstract classes can have constructors, fields, and access modifiers on members. Interfaces traditionally couldn't, though modern C# allows default implementations.
When in doubt, prefer interfaces for flexibility - you can always add an abstract class later if shared implementation becomes necessary.
Challenge
EasyLet's build a media player system that demonstrates when to use interfaces versus abstract classes. You'll create a design where unrelated devices share playback behavior through an interface, while related media types share common implementation through an abstract class.
You'll organize your code across four files:
IPlayable.cs: Define an interface calledIPlayablein theMedianamespace. This interface represents the contract for anything that can play media - whether it's a phone, a TV, or a dedicated music player. It should declare a single methodPlay()that returns a string.MediaFile.cs: Define an abstract class calledMediaFilein theMedianamespace. This represents the shared foundation for all media files. It should have aTitleproperty (string) and aDurationproperty (int, representing seconds). Include a constructor that sets both values. Add a concrete method calledGetInfo()that returns"{Title} ({Duration}s)". Also declare an abstract methodGetType()that returns a string - each media type will define what kind of file it is.AudioFile.cs: Define anAudioFileclass in theMedianamespace that inherits fromMediaFileand implementsIPlayable. Add anArtistproperty (string). The constructor should accept title, duration, and artist. OverrideGetType()to return"Audio". ImplementPlay()to return"Playing audio: {Title} by {Artist}".Program.cs: In your main file, create anAudioFileusing input values. Demonstrate both aspects of the class: callGetInfo()andGetType()(inherited from the abstract class), then callPlay()(from the interface). Store the audio file in anIPlayablevariable and callPlay()again to show interface polymorphism.
You will receive three inputs:
- Song title
- Duration in seconds
- Artist name
Print the output in this format:
Info: {GetInfo() result}
Type: {GetType() result}
Direct: {Play() result}
Via Interface: {Play() result from IPlayable variable}For example, if the inputs are Bohemian Rhapsody, 354, and Queen, the output should be:
Info: Bohemian Rhapsody (354s)
Type: Audio
Direct: Playing audio: Bohemian Rhapsody by Queen
Via Interface: Playing audio: Bohemian Rhapsody by QueenNotice how AudioFile benefits from both approaches: it inherits shared implementation (GetInfo()) from the abstract class while also fulfilling the IPlayable contract. The abstract class provides code reuse for related media types, while the interface allows any unrelated class to be "playable" without sharing an inheritance hierarchy.
Cheat sheet
An interface defines a contract that classes must follow, without any implementation:
public interface IFlyable
{
void Fly();
}
public class Bird : IFlyable
{
public void Fly()
{
Console.WriteLine("Flapping wings");
}
}An abstract class provides both a contract and shared implementation:
public abstract class Vehicle
{
public string Brand { get; set; }
public void StartEngine()
{
Console.WriteLine("Engine started");
}
public abstract void Drive(); // Must be implemented
}
public class Car : Vehicle
{
public override void Drive()
{
Console.WriteLine("Driving on roads");
}
}Key differences:
- A class can implement multiple interfaces but inherit from only one abstract class
- Use interfaces when unrelated classes need to share behavior
- Use abstract classes when related classes share common code and state
- Abstract classes can have constructors, fields, and access modifiers
- Prefer interfaces for flexibility
Try it yourself
using System;
using Media;
class Program
{
public static void Main(string[] args)
{
// Read input values
string title = Console.ReadLine();
int duration = Convert.ToInt32(Console.ReadLine());
string artist = Console.ReadLine();
// TODO: Create an AudioFile using the input values
// TODO: Print Info: followed by the result of GetInfo()
// TODO: Print Type: followed by the result of GetType()
// TODO: Print Direct: followed by the result of Play()
// TODO: Store the audio file in an IPlayable variable
// TODO: Print Via Interface: followed by the result of Play() from the IPlayable variable
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesNamespaces & DirectivesIntro to Classes & ObjectsThe 'this' KeywordMethods and ParametersFields vs PropertiesConstructorsObject InitializersRecap - Simple Calculator4Inheritance
Basic Inheritance (:) SyntaxThe 'base' KeywordVirtual & Override KeywordsSealed ClassesThe 'object' Base ClassRecap - Employee Hierarchy7Advanced Features
Operator OverloadingIndexers (this[])ToString() OverrideExtension MethodsRecap - Custom List2Properties & Static Members
Auto-Implemented PropertiesRead/Write-Only PropertiesStatic Fields & MethodsStatic ClassesExpression-Bodied Members5Polymorphism & Interfaces
Compile vs Runtime PolyInterface vs Abstract ClassMultiple InterfacesExplicit InterfacesUpcasting & DowncastingRecap - Shape Calculator