SOLID Made Easy – Interface Segregation Principle Posted on November 25, 2015 by Benjamin Medina III The fourth principle in SOLID is the Interface Segregation Principle (ISP) which is a very simple principle and we must put into practice whenever we can. The Interface Segregation Principle states that 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 submodule. The principle states that when we create an interface we must make sure that all the methods in the interface are going to be used by all the classes that will implement it. If we are going to violate the previous statement, not only are we violating the interface segregation principle but also the Liskov Substitution Principle as well as it will be forced to throw an exception for those methods that would not be used. It also states that if an interface is getting big, find a way to group the methods and create a separate interface for each group. The word “big” is subjective and it could lead to confusion if we think of it quantitatively i.e. if the number of methods in the interface is at least 5 then it is a big interface. What we should focus on is to determine if the method still belongs to the group or if we can create a separate interface for it. //// Incorrect way //// The interface for a restaurant transaction public interface ITransaction { void CreateTransaction(); void AddOrder(); void AddCustomerInfo(); } //// The delivery transaction class for customers who called the restaurant for a delivery public class DeliveryTransaction : ITransaction { public void CreateTransaction() { //// the code that creates the transaction } public void AddOrder() { //// the code that adds an order to the transaction } public void AddCustomerInfo() { //// the code that adds the customer info for the delivery } } //// The dine in transaction class for customers who currently dines in the restaurant public class DineInTransaction : ITransaction { public void CreateTransaction() { /*the code that creates the transaction*/ } public void AddOrder() { /*the code that adds an order to the transaction*/} public void AddCustomerInfo() { //// do nothing here or throw an exception } } 123456789101112131415161718192021222324252627282930313233343536373839 //// Incorrect way //// The interface for a restaurant transactionpublic interface ITransaction { void CreateTransaction(); void AddOrder(); void AddCustomerInfo(); } //// The delivery transaction class for customers who called the restaurant for a deliverypublic class DeliveryTransaction : ITransaction { public void CreateTransaction() { //// the code that creates the transaction } public void AddOrder() { //// the code that adds an order to the transaction } public void AddCustomerInfo() { //// the code that adds the customer info for the delivery }} //// The dine in transaction class for customers who currently dines in the restaurantpublic class DineInTransaction : ITransaction { public void CreateTransaction() { /*the code that creates the transaction*/ } public void AddOrder() { /*the code that adds an order to the transaction*/} public void AddCustomerInfo() { //// do nothing here or throw an exception }} Looking at this sample code, we can see that we are not just violating the interface segregation principle but also the Liskov substitution principle. For a dine in transaction, we do not need to add the customer information to the transaction; it may not look that bad based on the code sample but keep in mind that is on its simplest form, it only shows three methods but in reality it can contain more e.g. void transaction, cancel order, update customer info, etc. it is possible that a class that will implement the ITransaction will not use several methods that belong to the interface. //// Correct way //// The interface for the transaction public interface ITransaction { void CreateTransaction(); } //// The interface for the orders public interface IOrder { void AddOrder(); } //// The interface for the customer information public interface ICustomer { void AddCustomerInfo(); } //// The delivery transaction class for customers who called the restaurant for a delivery public class DeliveryTransaction : ITransaction, IOrder, ICustomer { public void CreateTransaction() { //// the code that creates the transaction } public void AddOrder() { //// the code that adds an order to the transaction } public void AddCustomerInfo() { //// the code that adds the customer info for the delivery } } //// The dine in transaction class for customers who currently dines in the restaurant public class DineInTransaction : ITransaction, IOrder { public void CreateTransaction() { /*the code that creates the transaction*/ } public void AddOrder() { /*the code that adds an order to the transaction*/} } 123456789101112131415161718192021222324252627282930313233343536373839404142 //// Correct way //// The interface for the transactionpublic interface ITransaction { void CreateTransaction(); } //// The interface for the orderspublic interface IOrder { void AddOrder();} //// The interface for the customer informationpublic interface ICustomer { void AddCustomerInfo();} //// The delivery transaction class for customers who called the restaurant for a deliverypublic class DeliveryTransaction : ITransaction, IOrder, ICustomer { public void CreateTransaction() { //// the code that creates the transaction } public void AddOrder() { //// the code that adds an order to the transaction } public void AddCustomerInfo() { //// the code that adds the customer info for the delivery }} //// The dine in transaction class for customers who currently dines in the restaurantpublic class DineInTransaction : ITransaction, IOrder { public void CreateTransaction() { /*the code that creates the transaction*/ } public void AddOrder() { /*the code that adds an order to the transaction*/} } By creating separate interfaces for each module that is a part of the restaurant transaction, we can easily select which modules to implement for a particular transaction. By only implementing the interfaces that we need, we are able to omit the methods that are not needed for a particular transaction i.e. the add customer info for the dine-in transaction. We also enable ourselves and other developers to easily implement and to use the interfaces since they only focus on a specific module. The interface segregation principle allows us to maximize the usage of interfaces and by putting this principle into practice, there is a possibility that we will be able to avoid the violation of previous principles that were discussed namely the single responsibility principle, the open-closed principle, and the Liskov substitution principle. It may be a simple principle, but we can clearly see the importance of constantly practicing this as it has a huge effect on our code.