Understanding SOLID – Interface Segregation Principle

In this article, let's talk in detail about partial interfaces and how Interface Segregation Principle solves this with examples.

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

Ram
Ram

I'm a full-stack developer and a software enthusiast who likes to play around with cloud and tech stack out of curiosity. You can connect with me on Medium, Twitter or LinkedIn.

Privacy Overview
Referbruv

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.

Strictly Necessary Cookies

Strictly Necessary Cookie should be enabled at all times so that we can save your preferences for cookie settings.

3rd Party Cookies

This website uses Google Analytics to collect anonymous information such as the number of visitors to the site, and the most popular pages.

Keeping this cookie enabled helps us to improve our website.