Building S.O.L.I.D - Interface Segregation Principle

The Interface Segregation Principle, the 'I' in S.O.L.I.D, states that no client should be forced to implement functionality that it does not use. Put simply, many interfaces with limited scopes are better than fewer, monolithic interfaces, valuing composition over inheritance. An example of this is noted below.

public interface IReport {
    string GetHtmlVersion();
    string GetCsvVersion();
    string GetXlsVersion();
}

public class SalesReport : IReport {
    /*
        This report is generated by a tool and needs to be exported
        to the web. We only want to use the GetHtmlVersion 
        function here but must implement the others also.  
    */
}

public class UserReport : IReport {
    /*
        This report is created by the app and needs to be in an
         machine-readable format. We only want to use the GetCsvVersion 
        function here but must implement the others also.  
    */
}

Both UserReport and SalesReport implement the IReport interface. The IReport interface specifies multiple methods which all classes using it must implement. However, in the case above, this does not make sense. As the SalesReport needs to be rendered to a web page, it only makes sense to implement the GetHtmlVersion function. Likewise, the UserReport needs to be machine readable, and would only require the GetCsvVersion function. Neither class has an XLS encoded body, so neither need to implement it. However, since all functions are tied up under the same interface, all must implement functionality they do not use. This is in violation of the Interface Segregation Principle.

To fix this, we could split the monolithic IReport interface into multiple, segregated and smaller interfaces, as shown below:

/*
    Smaller, segregated interfaces for specific uses. 
*/

public interface IHtmlReport {
    string GetHtmlVersion();
}

public interface ICsvReport {
    string GetCsvVersion();
}

public interface IXlsReport {
    string GetXlsVersion();
}

public class SalesReport : IHtmlReport {

}

public class UserReport : ICsvReport {

}

The new version of the code exposes fine-grained interfaces to each of the reports. The SalesReport, which needs only the GetHtmlVersion function, does not have to implement functions is does not use. This reduces junk code and keeps our objects clean and functional.

Adhering to the Interface Segregation Principle provides code that is/has:

  • Easier to read and maintain (smaller code blocks & fine grained interfaces)
  • Easier to navigate (functionality segregated into individual interfaces)
  • Low coupling between clients (plug-able extensibility with fine grained interfaces)

This article is my 4th oldest. It is 395 words long, and it’s got 0 comments for now.