The Interface Segregation Principle (ISP) is the fourth principle in the SOLID set of design principles. These principles guide the development of robust, flexible, and maintainable software components.
What is the Interface Segregation Principle?
Clients should not be forced to depend on methods that they do not use.
This means that interfaces provided to client components must be designed in such a way that they contain only the methods that are relevant to those clients. Interfaces should be tailored to the specific needs of their clients.
The Problem with Fat or Partial Interfaces
In the early stages of application development, it’s common to place all logic into a single class. As the application grows, these classes become bloated or “fat” with unrelated responsibilities.
Later, when we try to extract interfaces from these classes for modularity or extension, we may end up with interfaces containing many unrelated methods.
As a result:
- It may also violate the Liskov Substitution Principle (LSP) because classes cannot fully substitute their interfaces if they leave methods unimplemented or throw exceptions.
- Components are forced to implement methods they don’t need.
- This causes unnecessary code and confusion.
- This violates the Interface Segregation Principle (ISP)
The interfaces must be designed such that they are small and cohesive, and must serve a single responsibility. This is also a facet of the Single Responsibility; the first SOLID principle which has been discussed before
Example: Problem with Fat Interfaces
Let’s consider an interface ILogic
that defines methods for calculating areas and volumes:
public interface ILogic {
int CalculateArea(int side);
int CalculateArea(int length, int breadth);
int CalculateVolume(int side);
int CalculateVolume(int length, int breadth, int height);
}
Now, suppose we have a class SquareLogic that deals only with calculating the area of a square, which requires only one method.
However, because the class must implement the entire ILogic interface, it ends up with unnecessary methods:
public class SquareLogic : ILogic {
public int CalculateArea(int side) {
return side * side;
}
public int CalculateArea(int length, int breadth) {
throw new NotImplementedException();
}
public int CalculateVolume(int side) {
throw new NotImplementedException();
}
public int CalculateVolume(int length, int breadth, int height) {
throw new NotImplementedException();
}
}
This is a clear violation of the Interface Segregation Principle, because the class is forced to implement methods it doesn’t use.
It also violates the Liskov Substitution Principle since SquareLogic cannot fully substitute the ILogic type without runtime errors.
Solution: Break Down the Interface
To fix this, we break the ILogic interface into smaller, more cohesive interfaces, each with a single responsibility:
public interface ISquare {
int CalculateArea(int side);
}
public interface IRectangle {
int CalculateArea(int length, int breadth);
}
public interface ICube {
int CalculateVolume(int side);
}
public interface ICuboid {
int CalculateVolume(int length, int breadth, int height);
}
// Legacy interface for backward compatibility
public interface ILogic : ISquare, IRectangle, ICube, ICuboid {}
Each interface now serves a specific and well-defined purpose. Now each logic class can implement only the interface it needs:
public class SquareLogic : ISquare {
public int CalculateArea(int side) {
return side * side;
}
}
public class RectangleLogic : IRectangle {
public int CalculateArea(int length, int breadth) {
return length * breadth;
}
}
Usage in a Client Class
public class Client {
private readonly ISquare _square;
public Client() {
_square = new SquareLogic();
// SquareLogic is fully substitutable for ISquare
}
public void Invoke() {
Console.WriteLine(_square.CalculateArea(2));
}
}
Conclusion
By applying the Interface Segregation Principle:
- Classes implement only the interfaces they need.
- We avoid forcing implementations of irrelevant methods.
- Interfaces become smaller, cohesive, and easier to maintain.
- Our code better adheres to both Single Responsibility (SRP) and Liskov Substitution (LSP) principles.
- We can still preserve backward compatibility by composing a larger interface (
ILogic
) from the smaller ones.
This leads to cleaner architecture, improved scalability, and better maintainability as the application grows.
Last Updated 12th Oct 2025