SOLID — Interface Segregation Principle

Alex
4 min readDec 7, 2023

--

The Interface Segregation Principle explains that clients should not be forced to implement interfaces they do not use. Interfaces should be smaller and more compact to prevent clients becoming dependent on methods that are irrelevant.

An example being if we wanted to make an app to help us book a holiday abroad. We may only need certain features such as booking flights and finding a hotel. However, we wouldn’t really need features such as buying clothes or organising dog care for the week since they are not specifically related to booking a holiday abroad.

Examples of ISP violation

Overweight/Fat Interfaces

An overweight/fat interface contains too many methods, some of which may be unrelated and unnecessary. Implementing an interface such as this can lead to interfaces being forced to depend on methods they don’t need which can lead to bloated code and increased coupling.

What is an interface?

Interfaces are basically contracts which define properties, events and methods that classes or structs can implement.

When a class or struct implements an interface the item will be forced to implement the functionality that is defined in the interfaces. This enables the class to be used in a polymorphic way as it is following the contract specified in the interface.

Start of C# example

Create a new console application project using your chosen IDE and in the root of the project create an interfaced called IPrinterTasks.cs and paste in the below.

public interface IPrinterTasks 
{
void Print(string content);
void Scan(string content);
void Fax(string content);
void PrintDuplex(string duplexContent);
}

We will now create a class called CanonPrinter.cs with the below content.

public class CanonPrinter : IPrinterTasks
{
public void Print(string content)
{
Console.WriteLine($"{content}");
}

public void Scan(string content)
{
Console.WriteLine($"{content}");
}

public void Fax(string content)
{
Console.WriteLine($"{content}");
}

public void PrintDuplex(string duplexContent)
{
Console.WriteLine($"{duplexContent}");
}
}

In addition, create another class called LiquidInkPrinter.cs

public class LiquidInkPrinter : IPrinterTasks
{
public void Print(string content)
{
Console.WriteLine("${content}");
}

public void Scan(string content)
{
throw new NotImplementedException();
}

public void Fax(string content)
{
Console.WriteLine("${content}");
}

public void PrintDuplex(string content)
{
throw new NotImplementedException();
}

}

So we will have to implement every method of the interface within both classes in order for the code to not error, however, our requirement is for the CanonPrinter.cs to implement all methods but the LiquidInkPrinter.cs only wants the Print and Fax methods to be implemented so this is violating the Interface Segregation Principle.

Implement Interface Segregation Principle

To implement IIP we can split up the interface into 3 smaller interfaces, so since both classes want to implement Print and Scan methods we can keep those methods in the IPrinterTasks.cs interface. However, only the CanonPrinter class implements the Fax and PrintDuplex methods. So we will create an interface for both of these methods. Create two interfaces one called IFax and another called IPrintDuplex.

public interface IFax
{
void Fax(string content);
}
public interface IPrintDuplex
{
void PrintDuplex(string duplexContent);
}

So now for a class to implement all of the methods i.e. CanonPrinter it will have to implement all 3 interfaces, whereas, with our LiquidInkPrinter we only have to use the IPrinterTasks since it only wants to implement the Print and Scan methods.

public class CanonPrinter : IPrinterTasks,IFax,IPrintDuplex
{
public void Print(string content)
{
Console.WriteLine($"{content}");
}

public void Scan(string content)
{
Console.WriteLine($"{content}");
}

public void Fax(string content)
{
Console.WriteLine($"{content}");
}

public void PrintDuplex(string duplexContent)
{
Console.WriteLine($"{duplexContent}");
}
}
public class LiquidInkPrinter : IPrinterTasks
{
public void Print(string content)
{
Console.WriteLine($"{content}");
}

public void Scan(string content)
{
Console.WriteLine($"{content}");
}
}

Now because we have separated the interfaces and in our classes only implementing the necessary interfaces within those classes then we are following the Interface Segregation Principle.

We can test that this works by opening the Program.cs code and pasting the below code.

CanonPrinter canonPrinter = new CanonPrinter();
canonPrinter.Print("Canon Printer print");
canonPrinter.Fax("Fax");
canonPrinter.PrintDuplex("Print Duplex");
canonPrinter.Scan(" Canon Printer Scan");

LiquidInkPrinter liquidInkPrinter = new LiquidInkPrinter();
liquidInkPrinter.Print("Liquid ink printer print");
liquidInkPrinter.Scan("Liquid ink printer scan");

When you go through the intellisense of liquidInkPrinter you can see we only have access to the Print and Scan methods, and if you run the above code you’ll see the below.

I hope you enjoyed this article and learned something don’t forget to clap, follow and share!

--

--

No responses yet