Saturday, December 10, 2016

ISP - Interface Segregation Principle

ISP says - Many client-specific interfaces are better than one general-purpose interface. 
(The clients should not be forced to implement interfaces they don't use. Instead of one fat interface many small interfaces are preferred based on groups of methods, each one serving one sub module.)

This means that create the interfaces such a way that it is closely related to the code that uses it than the code which is going to implement it (Basically it says that define interfaces based on the methods which clients need than which method class implements). So that clients are not forced to implement the interfaces which they do not use.

Basically ISP is nothing but Interface Re-engineering.  

Let's see ISP with an example, suppose we have an application to print Documents and PDFs, we can print the Documents and PDFs either in colour or no-colour.

interface IPrint{
     public void Print();
     public void SetColour();
}

class Document : IPrint{
  // interface or other implementation goes here
}

class PDF: IPrint {
  // interface or other implementation goes here
}

Lets say now a new requirement comes to add the TextDocument. As we already have IPrint interface we can ask TextDocument to implement the interface IPrint but then the TextDocument class doesn't need SetColour() method because text are never required to be printed in colour. How do we over come this issue? This is where the ISP comes into the picture.

First lets try to divide IPrint interface to two interface as below:
interface IPrint{
   public void Print();
}

interface IColour {
   public SetColour();
}

Then ask new class TextDocument to implement IPrint() and existing classes to implement IColour as well as IPrint. Well, this would be wrong as it violates OCP in existing Document and PDF classes (since we are modifying them to implement the new interface). We shouldn't be modifying the exiting classes, so how should we resolve this issues now?

Well, this can be done easily, by introducing a new interface IBasePrint and moving Print() method in it and making interface IPrint and class TextDocument to implements interface IBasePrint.

interface IBasePrint{
    public Print();
}

inteface IPrint : IBasePrint
{
     public SetColour();
}

class TextDocument: IBasePrint
{
  // interface or other implementation goes here
}

PS: Like Classes, each interface should have a specific purpose/responsibility (refer to SRP). Don't force the class to implement an interface when object doesn't share the purpose. The larger the interface, the more likely it includes methods that are not required by all implementer. 

No comments:

Post a Comment