Summary: in this tutorial, you’ll learn about the C# Interface Segregation Principle (ISP) that promotes the idea of creating small and focused interfaces that are specific to the needs of clients.
Introduction to the C# Interface Segregation Principle
The interface segregation principle is the fourth principle in the five SOLID principles of object-oriented design:
- Single Responsibility Principle (SRP)
- Open-Closed Principle (OCP)
- Liskov Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
The interface segregation principle suggests that you should not force a client to implement an interface that contains methods that it doesn’t need.
Instead, you should break down larger interfaces into smaller ones that are more focused and targeted to specific use cases.
The interface segregation principle promotes the idea of creating small and cohesive interfaces that are specific to the client’s needs.
Let’s take an example of violating the interface segregation principle:
namespace ISP;
public interface IVehicle
{
void Run();
void Fly();
}
public class Aircraft : IVehicle
{
public void Run() => Console.Write("Running");
public void Fly() => Console.Write("Flying");
}
public class Car: IVehicle
{
public void Run() => Console.Write("Running");
public void Fly() => throw new NotImplementedException();
}
public class Program
{
public static void Main(string[] args)
{
// aircraft
var aircraft = new Aircraft();
aircraft.Run();
aircraft.Fly();
// car
var car = new Car();
car.Run();
// cannot fly, exception
car.Fly();
}
}
Code language: C# (cs)
How it works.
First, define an interface IVehicle
interface that has two methods Run()
and Fly()
:
public interface IVehicle
{
void Run();
void Fly();
}
Code language: C# (cs)
Second, define an Aircraft
class that implements the IVehicle
interface:
public class Aircraft : IVehicle
{
public void Run() => Console.Write("Running");
public void Fly() => Console.Write("Flying");
}
Code language: C# (cs)
Third, define a Car
class that also implements the IVehicle
interface. Since a regular car cannot fly, it raises an exception in the Fly()
method:
public class Car: IVehicle
{
public void Run() => Console.Write("Running");
public void Fly() => throw new NotImplementedException();
}
Code language: C# (cs)
Finally, create an Aircraft
object and call the Run()
and
methods. But when we create a Fly()
Car
object and call the
method, it raises an exception:Fly()
public class Program
{
public static void Main(string[] args)
{
// aircraft
var aircraft = new Aircraft();
aircraft.Run();
aircraft.Fly();
// car
var car = new Car();
car.Run();
// cannot fly, exception
car.Fly();
}
}
Code language: C# (cs)
This is an example of violating the Interface Segregation Principle because the IVehicle
forces the Car
class to use the Fly()
method that it doesn’t need.
Refactoring the program to conform with the Interface Segregation Principle
To fix the issue of violating the interface segregation principle, you need to break down the large interface into smaller ones.
First, segregate the IVehicle
interface into two smaller interfaces IFlyable
and IRunnable
:
public interface IFlyable
{
void Fly();
}
public interface IRunnable
{
void Run();
}
Code language: C# (cs)
Second, define the Aircraft
class that implements both interfaces since the Aircraft
class needs both Run()
and Fly()
methods:
public class Aircraft : IRunnable, IFlyable
{
public void Run() => Console.Write("Running");
public void Fly() => Console.Write("Flying");
}
Code language: C# (cs)
Third, define the Car
class that implements only the IRunnable
interface because it only needs the Run()
method:
public class Car: IRunnable
{
public void Run() => Console.Write("Running");
}
Code language: C# (cs)
Finally, create Aircraft
and Car
objects and call their methods respectively in the Main()
method of the Program
class:
public class Program
{
public static void Main(string[] args)
{
// aircraft
var aircraft = new Aircraft();
aircraft.Run();
aircraft.Fly();
// car
var car = new Car();
car.Run();
}
}
Code language: C# (cs)
Put it all together.
namespace ISP;
public interface IFlyable
{
void Fly();
}
public interface IRunnable
{
void Run();
}
public class Aircraft : IRunnable, IFlyable
{
public void Run() => Console.Write("Running");
public void Fly() => Console.Write("Flying");
}
public class Car: IRunnable
{
public void Run() => Console.Write("Running");
}
public class Program
{
public static void Main(string[] args)
{
// aircraft
var aircraft = new Aircraft();
aircraft.Run();
aircraft.Fly();
// car
var car = new Car();
car.Run();
}
}
Code language: C# (cs)
Summary
- C# Interface Segregation Principle (ISP) advocates for small, client-specific interfaces.