Learn Interface Segregation Principle (ISP)

Introduction

In this article, we will cover the Interface Segregation Principle (ISP)

Interface Segregation Principle (ISP)

  • ISP states that "Clients should not be forced to depend upon interfaces that they do not use."
  • A good example to look at that demonstrates this principle is for classes that require large settings objects. Not requiring clients to setup huge amounts of options is beneficial, because most of the time they won't need all of the settings. Making them optional helps prevent having a "fat interface".

Let’s take an example of Manage Products in a Store.

Imagine we have an online store system where you manage products. Not all products are the same; some are downloadable, like e-books, while others are physical products, like clothes.

Violation of ISP/Bad Code

using System;

namespace DesignPattern
{
    public interface IProduct
    {
        void SetPrice(decimal price);
        void GetDescription();
        byte[] Download(); // This does not apply to all products!
        void ShipTo(string address); // This does not apply to downloadable products!
    }

    public class Ebook : IProduct
    {
        public void SetPrice(decimal price)
        {
            // Implementation
        }

        public void GetDescription()
        {
            // Implementation
        }

        public byte[] Download()
        {
            byte[] ebook = new byte[1000];
            // Return the e-book file
            return ebook;
        }

        public void ShipTo(string address)
        {
            throw new NotImplementedException("Ebooks cannot be shipped!");
        }
    }
}

Note. In the above example, the Ebook class is forced to implement the ShipTo method, which doesn’t make sense for e-books.

Using ISP / Good Code

using System;

namespace DesignPattern
{
    public interface IProduct
    {
        void SetPrice(decimal price);
        void GetDescription();
    }

    public interface IDownloadable
    {
        byte[] Download();
    }

    public interface IShippable
    {
        void ShipTo(string address);
    }

    public class Ebook : IProduct, IDownloadable
    {
        public void SetPrice(decimal price)
        {
            // Implementation
            Console.WriteLine($"Price Set EBook: {price}");
        }

        public void GetDescription()
        {
            // Implementation
            Console.WriteLine("Get Description : EBook");
        }

        public byte[] Download()
        {
            Console.WriteLine("Download EBook");
            // Return the e-book file
            return new byte[1000];
        }
    }

    public class TShirt : IProduct, IShippable
    {
        public void SetPrice(decimal price)
        {
            // Implementation
            Console.WriteLine($"Price Set TShirt: {price}");
        }

        public void GetDescription()
        {
            // Implementation
            Console.WriteLine("Get Description : TShirt");
        }

        public void ShipTo(string address)
        {
            // Ship the t-shirt to the given address
            Console.WriteLine($"TShirt ShipTo : {address}");
        }
    }

    //Testing the Interface Segregation Principle
    public class Program
    {
        public static void Main()
        {
            Ebook ebook = new Ebook();
            ebook.SetPrice(1000);
            ebook.GetDescription();
            ebook.Download();

            TShirt shirt = new TShirt();
            shirt.SetPrice(2000);
            shirt.GetDescription();
            shirt.ShipTo("Address 1, City, Pindcode");
            Console.ReadKey();
        }
    }
}

ISP

Note. Now, with the segregated interfaces, each product class only implements the methods relevant to its type. The Ebook class no longer has to deal with the irrelevant ShipTo method, and the system becomes clearer and easier to maintain.