Skip to content

Create and implement your own interfaces.

Become a developer with our complete learning paths
Become a developer with our complete learning paths

Introduction

In this lesson, you will learn how to create and implement your own interfaces with a concrete example and you will get an idea of why interfaces are useful especially when our classes don’t have a relationship with each other and therefore they don’t share a base class.

Example

Imagine that we are working on a video game where the player can destroy stuff, But everything we destroy will have different behavior depending on what is destroyed.

for example, destroying a Chair will play some destruction sounds and will spawn destroyed chair parts, but destroying a car will play an explosion sound, create fire and destroy other objects nearby.

For our game we have the following classes:

  • Chair that inherits from class Furniture
  • Car that inherits from class vehicle

//base class for furnitures
class Furniture {
		//color of the furniture
    public string Color { get; set; }
	  //material of the furniture
	  public string Material { get; set; }
		//default constructor
    public Furniture() {
        Color = "White";
        Material = "Wood";
    }

		//simple constructor
    public Furniture(string color,string material) {
        Color = color;
        Material = material;
    }

}

//base class for vehicles
class Vehicle {
		//speed of the vehicle
    public float Speed { get; set; }
		//color of the vehicle
    public string Color { get; set; }
		//default constructor
    public Vehicle() {
        Speed = 120f;
        Color = "White";
    }
		//simple constructor
    public Vehicle(float speed,string color) {
        Speed = speed;
        Color = color;
    }
}

//subclass chair that extends Furniture 
class Chair: Furniture {

	    //simple constructor
	    public Chair(string color,string material) {
	        this.Color = color;
	        this.Material = material;
	    }

}

//subclass Car that extends Vehicle
class Car: Vehicle{   
		//simple constructor
    public Car(float speed,string color){
        this.Speed = speed;
        this.Color = color;

    }
}

Now what is the best approach to add this destruction feature?

If we think about it, we can’t add a class to make our classes inherit because C# is a single inheritance language and not multi-inheritance. We already inherited from one class.

Plus, there is no concrete relationship between a car and a chair to share one base class anyways.

If we implement normal methods called Destroy in each class, it will be hard to maintain. What if we decide to change the destruction system entirely or add visual effects to our destructible objects? It will be a pain actually to go through each class and modify it.

What we need is a way to enforce our destructible behavior on every class that uses it just like a contract :)

The best approach, in this case, is to use an Interface we will call it IDestroyable, and any class that implements this interface will be forced to follow our destruction requirements and customize it at the same time depending on the class itself.

This interface will define two things

  • A property called DestructionSound which will store the audio file for the destruction sound
  • A method called Destroy which each class will implement differently
//defining an interface called IDestroyable 
interface IDestroyable {
			//property to store the audio file of the destruction sound
      string DestructionSound { get; set; }
				//method to destroy an object
        void Destroy();

    }

Now let’s make our classes implement this interface and implement the interface’s content

//implementing the interface IDestroyable 
class Chair: Furniture, IDestroyable {
		//implementing the interface's property
    public string DestructionSound { get; set; }

    public Chair(string color,string material) {

        this.Color = color;
        this.Material = material;
				//initializing the interface's property with a value in the constructor
        DestructionSound = "ChairDestructionSound.mp3";
    }

		//implementing the interface's method
    public void Destroy() {
				//when a chair gets destroyed we should play the destruction sound
				//and spawn the destroyed chair parts
        Console.WriteLine($"The {Color} chair was destroyed");
        Console.WriteLine("Playing destruction sound {0}",DestructionSound);
        Console.WriteLine("Spawning chair parts");
    }

}
//implementing the interface IDestroyable
class Car: Vehicle, IDestroyable{
		//implementing the interface's property
    public string DestructionSound { get; set; }

		//creating a new property to store the destroyable objects nearby
		//when a car gets destroyed it should also destroy the nearby object
		//this list is of type IDestroyable which means it can store any object
		//that implements this interface and we can only access the properties and
		//methods in this interface
    public List<IDestroyable> DestoryablesNearby;

    public Car(float speed,string color){
        this.Speed = speed;
        this.Color = color;
				//initialize the interface's property with a value in the constructor
        DestructionSound = "CarExplosionSound.mp3";
				//initialize the list of destroyable objects
        DestoryablesNearby = new List<IDestroyable>();
    }

		//implementing the interface's method
    public void Destroy() {
				//when a car gets destroyed we should play the destruction sound
				//and create fire effect
        Console.WriteLine("Playing destruction sound {0}", DestructionSound);
        Console.WriteLine("Create fire");
				//go through each destoryable object nearby and call it's destroy method
        foreach(IDestroyable destroyable in DestoryablesNearby) {
            destroyable.Destroy();
        }

    }
    

This way, if we decide to add a property or a method to our interface, for example: Delete destroyed objects, after some time, all classes that implement this interface will be forced to follow the new requirements since now they are part of the interface’s contract :).

Now let’s go to our main method and create few objects of each class and use try the new destruction feature

using System;
using System.Collections.Generic;

namespace OOPInterfaces {
    class Program {
        static void Main(string[] args) {
	          //creating two objects of type chair
            Chair officeChair = new Chair("Brown", "Plastic");
            Chair gamingChair = new Chair("Red", "Wood");
						//creating a new object of type car
            Car damagedCar = new Car(80f, "Blue");
						//add the two chairs to the IDestroyable list of the car
						//so that when we destroy the car the destroyable objects
						//that are near the car will get destroyed as well
            damagedCar.DestoryablesNearby.Add(officeChair);
            damagedCar.DestoryablesNearby.Add(gamingChair);
						 
						//pause
            Console.ReadKey();

        }

    }
}

Important note: Interfaces are used for Communication between 2 similar/nonsimilar classes, which do not care about the type of the class implementing the Interface, just like how our car communicated with the chair to call the Destroy method, all because they implemented the same interface.

While interfaces might seems hard to understand at first glance, they provide us with great perks, for example:

  • Code readability: An interface constitutes a declaration about intentions. It defines the capability of your class, what your class is capable of doing. If you implement ISortable, you’re clearly stating that objects of your class can be sorted.
  • Code semantics: By providing interfaces and implementing them, you’re actively separating concepts. An interface defines a behavioral model, a definition of what an object can do. Separating those concepts keeps the semantics of your code more clear.
  • Code maintainability: Interfaces help reduce coupling and allow you to easily interchange implementations for the same concept without the underlying code being affected.
  • Design Patterns: It’s the bigger picture of using contracts, abstraction, and interfaces pivotal for OOP, human understanding, and complex system architectures.
  • Multiple inheritance: complex Using interfaces can be our gateway to use multiple inheritances in C#

Outro

Suppose you write a library and want it to be modifiable by users. You write the interface and its class implementation. Other developers who will use your library can still write their own implementation class, which may use different technology/algorithms that achieve the same result. This is also why we meet so many interfaces in libraries we use but rarely feel the need to write our own interfaces because we don’t write libraries.

On a final note, the important thing is to understand how interfaces are implemented at this point of the course. As we go through different technologies like WPF and ASP.Net, we will start using interfaces more, which will help us better understand them in the future.

Complete Code

using System;
using System.Collections.Generic;

namespace OOPInterfaces {
    class Program {
        static void Main(string[] args) {
	          //creating two objects of type chair
            Chair officeChair = new Chair("Brown", "Plastic");
            Chair gamingChair = new Chair("Red", "Wood");
						//creating a new object of type car
            Car damagedCar = new Car(80f, "Blue");
						//add the two chairs to the IDestroyable list of the car
						//so that when we destroy the car the destroyable objects
						//that are near the car will get destroyed as well
            damagedCar.DestoryablesNearby.Add(officeChair);
            damagedCar.DestoryablesNearby.Add(gamingChair);
						//destory the car
            damagedCar.Destroy();
						//pause
            Console.ReadKey();

        }

    }

//base class for furnitures
class Furniture {
		//color of the furniture
    public string Color { get; set; }
	  //material of the furniture
	  public string Material { get; set; }
		//default constructor
    public Furniture() {
        Color = "White";
        Material = "Wood";
    }

		//simple constructor
    public Furniture(string color,string material) {
        Color = color;
        Material = material;
    }

}

//base class for vehicles
class Vehicle {
		//speed of the vehicle
    public float Speed { get; set; }
		//color of the vehicle
    public string Color { get; set; }
		//default constructor
    public Vehicle() {
        Speed = 120f;
        Color = "White";
    }
		//simple constructor
    public Vehicle(float speed,string color) {
        Speed = speed;
        Color = color;
    }
}

//defining an interface called IDestroyable 
interface IDestroyable {
			//property to store the audio file of the destruction sound
      string DestructionSound { get; set; }
				//method to destroy an object
        void Destroy();

    }

//implementing the interface IDestroyable 
class Chair: Furniture, IDestroyable {
		//implementing the interface's property
    public string DestructionSound { get; set; }

    public Chair(string color,string material) {

        this.Color = color;
        this.Material = material;
				//initializing the interface's property with a value in the constructor
        DestructionSound = "ChairDestructionSound.mp3";
    }

		//implementing the interface's method
    public void Destroy() {
				//when a chair gets destroyed we should play the destruction sound
				//and spawn the destroyed chair parts
        Console.WriteLine($"The {Color} chair was destroyed");
        Console.WriteLine("Playing destruction sound {0}",DestructionSound);
        Console.WriteLine("Spawning chair parts");
    }

}
//implementing the interface IDestroyable
class Car: Vehicle, IDestroyable{
		//implementing the interface's property
    public string DestructionSound { get; set; }

		//creating a new property to store the destroyable objects nearby
		//when a car gets destroyed it should also destroy the nearby object
		//this list is of type IDestroyable which means it can store any object
		//that implements this interface and we can only access the properties and
		//methods in this interface
    public List<IDestroyable> DestoryablesNearby;

    public Car(float speed,string color){
        this.Speed = speed;
        this.Color = color;
				//initialize the interface's property with a value in the constructor
        DestructionSound = "CarExplosionSound.mp3";
				//initialize the list of destroyable objects
        DestoryablesNearby = new List<IDestroyable>();
    }

		//implementing the interface's method
    public void Destroy() {
				//when a car gets destroyed we should play the destruction sound
				//and create fire effect
        Console.WriteLine("Playing destruction sound {0}", DestructionSound);
        Console.WriteLine("Create fire");
				//go through each destoryable object nearby and call it's destroy method
        foreach(IDestroyable destroyable in DestoryablesNearby) {
            destroyable.Destroy();
        }

    }

	}

}
Lost in coding? Discover our Learning Paths!
Lost in coding? Discover our Learning Paths!
Tired of being just an average developer?
Stop wasting your time and learn coding the right (and easy) way!
Tired of being just an average developer?
Stop wasting your time and learn coding the right (and easy) way!
Enter your email and we will send you the PDF guide:
Enter your email and we will send you the PDF guide