Click here to Skip to main content
Click here to Skip to main content

Interface Segregation Principle (ISP of SOLID in C#)- Walk through History

, 12 May 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Interface Segregation Principle - Walk through History

Introduction

This article explains what is Interface Segregation Principle and its uses. It is aimed at beginners and intermediate developers.

Interface Segregation Principle

The principle states that no client should be forced to depend on methods that it does not use (Wiki).

In other words, “What is the point in selling a horse saddle for one who does not own a horse?”

Disclaimer: The following discussion is inspired from Wikipedia. You will find the examples similar but elaborated for the sake of understanding.

History

Let's begin with a little bit of history.

Don't worry Smile | :) It's going to be interesting.

Xerox had created a new all in one printer system. The printer system could do a wide variety of jobs like printing, scanning, stapling, faxing, etc.

Xerox hired developers to develop software for that printer machine. Soon the software was developed and printer machine was working great.

But when the time progressed, maintaining the software became difficult and further development was a nightmare. Why? Well, we will see that in a short span of time. J

What Did Xerox Do?

Xerox hired a consultant to look at what was the problem. Here comes our hero, Martin. We will see what the problem was, how Martin proposed a solution and the birth of ISP.

The problematic code snippet is as follows:

// The code that violates ISP
interface IMachine
{
    public bool print(List<Item> item);
    public bool staple(List<Item> item);
    public bool fax(List<Item> item);
    public bool scan(List<Item> item);
    public bool photoCopy(List<Item> item);
}  
// Code implementing the IMachine interface. 

class Machine : IMachine
{
   public Machine()
   {
   }

   public bool print(List<Item> item)
   { 
      // Print the items.
      Console.WriteLine("All Items printed" + item.Count());
   }

   public bool staple(List<Item> item) 
   {
      // Staple the items.
      Console.WriteLine("Items stapled" + item.Count());
   }
 
   public bool fax(List<Item> item) 
   {
      // Fax the items.
      Console.WriteLine("All Items Faxed" + item.Count());
   }

   public bool scan(List<Item> item) 
   {
      // Scan the items.
      Console.WriteLine("All Items Scanned" + item.Count());
   }

   public bool photoCopy(List<Item> item) 
   {
      // Xerox the items.
      Console.WriteLine("All Items Photo copied" + item.Count()); 
   }
}  

Well, that is a straight forward code. But, wait!

Before scrolling down, try taking a minute to make a list of potential problems with the above code.

The Problems and the Pitfalls

Ok, here we go. J

Problems

1. Recompiling the entire code even when a minor change has to be made L

Even if you make a small modification, the entire code needs to be re-compiled wasting precious development time.

2. What happens when you supply this to a client who is interested only in printing job?

You are passing a DLL or a library which contains a bunch of unnecessary functions which are not all required to your client. He or she may get confused over these functions. Passing a printer function to a printer client makes sense. But, what good does it make passing a bunch of irrelevant functions?

3. Problem with “fat” Interfaces

Even though only the Print functionality is the only needed function for the printer-client, he/she might end up implementing some bunch of unwanted functions. Why are you forcing your printer client to implement scanning functionality even when they don't want it?

So What Did Martin Do?

Martin suggested a solution that gave birth to Interface Segregation Principle.

Here comes that:

  1. Break down the fat interface to smaller and meaningful role interfaces.
  2. In the above example, let the IMachine interface contain all the broken down interfaces Smile | :)
  3. Inject the implementations of smaller interfaces to Machine class (Dependency Injection).
// (The following interfaces are called as “Role Interfaces” as they serve their roles :))

interface IPrinter
{
    public bool print(List<Item> item);
}

interface IStaple
{
    public bool staple(List<Item> item);
}

interface IFax
{    
    public bool fax(List<Item> item);
}

interface IScan
{
    public bool scan(List<Item> item);
}

interface IPhotoCopy
{
    public bool photoCopy(List<Item> item);
}

interface IMachine : IPrinter, IFax, IScan, IPhotoCopy,IStaple
{
    public bool print(List<Item> item);
    public bool staple(List<Item> item);
    public bool fax(List<Item> item);
    public bool scan(List<Item> item);
    public bool photoCopy(List<Item> item);
}

class Machine : IMachine
{
      private IPrinter printer {get;set;}
      private IFax fax {get;set;}
      private IScan scan  {get;set;}
      private IPhotoCopy photocopy {get;set;}
      private IStaple staple {get;set;}
  
        // Notice how the dependencies are injected through constructor (constructor dependency injection)
      public  Machine(IPrinter printer, IFax fax, IScan scan, IPhotoCopy photoCopy, IStaple staple)
      {
         this.Printer = printer;
        this.fax = fax;    
        this.scan = scan;
        this.photoCopy = photocopy;
        this.staple = staple;
          }

      public bool print(List<Item> item)
         { 
          // Print the items.
          Console.WriteLine("All Items printed" + item.Count());
      }

      public bool staple(List<Item> item) 
      {
          // Staple the items.
          Console.WriteLine("Items stapled" + item.Count());
      }
 
      public bool fax(List<Item> item) 
      {
          // Fax the items.
          Console.WriteLine("All Items Faxed" + item.Count());
      }

      public bool scan(List<Item> item) 
      {
          // Scan the items.
          Console.WriteLine("All Items Scanned" + item.Count());
      }

      public bool photoCopy(List<Item> item) 
      {
          // Xerox the items.
          Console.WriteLine("All Items Photo copied" + item.Count()); 
      }
}

What Happens Afterwards?

1. A printer only client comes. What to do?

It’s simple. Create an instance of Printer class and give to him/her.

    IPrinter printer = new Printer();
    
    printer.print( //IDE shows that only the Print function is accessible. 
    // Clean, neat and separate.   

Note that here we are not forcing him to use a library that has unwanted functionality (like scanning, faxing, etc.). Our client wants only the printer functionality and we give him what he asked for using our "IPrinter" role interface. Our client is now happy because he got what he wanted. Smile | :)

2. A client wanting all the functionalities arrives. What to do?

Easy enough.

    IPrinter printer = new Printer();     //Printer implements IPrinter
    IScan scanner = new Scanner();
    IFax fax = new Fax();
    IPhotoCopy photocopy = new PhotoCopy();
    IStaple staple = new Staple();

    var allOneClient  = new Machine(printer, fax, scan, photoCopy, staple);  

Feels good. Huh?

And with that, I end how Martin formulated ISP.

Final Words

The Wiki says:

“The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use.”

  1. ISP splits interfaces which are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them.
  2. Such shrunken interfaces are also called role interfaces.
  3. ISP is intended to keep a system decoupled and thus easier to refactor, change, and redeploy.

I hope the above example covers every point. Happy OODing Smile | :)

-Madhuresh K

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

MadhureshK
Engineer
India India
No Biography provided

Comments and Discussions

 
BugInconsistent use of method name print/printer in example code PinmemberMember 1068568913-May-14 21:56 
GeneralStill in business? Pinmemberinfal13-May-14 2:13 
GeneralRe: Still in business? PinmemberMadhureshK13-May-14 2:36 
GeneralMy vote of 1 Pinmembercboozb30-Apr-14 16:13 
QuestionDI / IoC Pinmemberbbqchickenrobot30-Apr-14 2:17 
AnswerRe: DI / IoC PinmemberMadhureshK30-Apr-14 2:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141223.1 | Last Updated 12 May 2014
Article Copyright 2014 by MadhureshK
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid