Understanding SOLID Principles: Interface Separation
Tags: oop, beginners, solid, computerscience
Published: 2021-02-21 08:24:27

I know it's boring.

We have surpassed the halfway point in our SOLID series.

But for the love of god bear with me, and to celebrate we will cover something much easier today.

Interface Separation Principle

It's the "I" in SOLID, and in my opinion the easiest one to understand.

Without further ado, let us begin.

*PS. This principle is also called interface segregation, don't worry it's the same exact thing but named differently.*

## Table of Contents 

- [What is the "Interface Separation Principle"?](#1)
- [Why would I want to follow this principle?](#2)
- [Violations of the Interface Separation Principle](#3)
- [Refactoring our Pizza System](#4)
- [Conclusion](#5)
- [Additional Resources](#6)

## What is the "Interface Separation Principle"? <a name="1"></a>

If you googled this exact question it will lead you to a Wikipedia page, that says something like this:

> In the field of software engineering, the interface-separation principle (ISP) states that no client should be forced to depend on methods it does not use.

Okay, this is strangely in the world of Wikipedia, a simple explanation. For the sake of me having something to write, let me explain.

What it basically says is that an **interface** shouldn't **force** a **class** to implement methods that it won't be using. 

## Why would I want to follow this principle? <a name="2"></a>

Let's look at an example where this principle is violated.

We will create an interface for our fictional pizza place, where a customer can order a pizza, soda, or a combo of both:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ogs7bty4ztx6k95hyhz5.png)

Since a customer can order pizza, or a drink, or both, we decided to put all order methods in a single interface.

Now, to implement a pizza-only order, we are forced to throw an exception in the `orderDrink()` method:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xcog79pyvg0bosvz2v2d.png)

Same thing for drink-only orders, we'd also need to throw an exception for `orderPizza()`

This design introduces many downsides:

- If we make a change to the `orderDrink()` parameters in the interface, we are gonna have to implement the revised function in the pizza-order class where it isn't being used.

By violating the interface separation principle, we face the following problems in our code:

1. Client developers are confused by the methods they don’t need.
2. Maintenance becomes harder because of side effects: a change in an interface forces us to change classes that don’t implement the interface.

This also forces us to violate other SOLID principles such as SRP (Single Responsibility Principle).

## Violations of the Interface Separation Principle <a name="3"></a>

Now we know why we don't want to violate this principle, but now let us discuss some code smells which could indicate a violation of the interface separation principle.

### Bulky Interfaces

When your interfaces are too bulky, it's highly doubtful that all your clients will use all the methods that the interface provides. The interface separation principle tells us that we need most, if not all of the methods in our interfaces, but in a bulky interface, we only need a few of them.

### Unused Dependencies

Another indication is when we pass `null` or equivalent value into a method. In our example, we can use `orderCombo()` to place a pizza-only order by passing zero as the drink parameter. This client does not require the drink dependency, so we should have a separate method in a different interface to order drinks.

### Methods Throwing Exceptions

As in our pizza example, if your methods throw unexpected exceptions, this is a code smell related to the interface separation principle. It might be a good time to refactor these classes.

## Refactoring our Pizza System <a name="4"></a>

The first thing we have to do is break down our order service interface into multiple smaller interfaces:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/umfhsttwbc83jczfajyj.png)

For the sake of simplicity, we can simply create separate classes for each type of order.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/svncxuf3g316mhlez4yk.png)

Here we created two separate classes that handle their specific orders. You may say that this is redundant and you may be true, there are a million better ways to implement an ordering system. But for the sake of the context of this post, this is enough. 

This design separated our concerns with a different kind of ordering system and made it a lot more flexible. Now `PizzaOrder` is not coupled with `DrinkOrder` and their changes don't affect each other.

## Conclusion <a name="5"></a>

In conclusion, the interface separation wants us to design our interfaces in a way that doesn't force clients to use unnecessary methods. Now someone might say, do I simply have a bunch of one method interfaces?

No. 

SOLID principles shouldn't be followed to the teeth, you are the developer and you know best where you can apply these principles in your project. 

Anyways, I hope you learned something today, and as always if you got any questions, leave them down in the comments.

## Additional Resources <a name="6"></a>

[https://reflectoring.io/interface-segregation-principle/](https://reflectoring.io/interface-segregation-principle/)

[https://dzone.com/articles/solid-principles-by-example-interface-segregation](https://dzone.com/articles/solid-principles-by-example-interface-segregation)

[https://www.youtube.com/watch?v=y1JiMGP51NE](https://www.youtube.com/watch?v=y1JiMGP51NE)

[https://en.wikipedia.org/wiki/Composition_over_inheritance](https://en.wikipedia.org/wiki/Composition_over_inheritance)