Interface Segregation Principle Using Python

Introduction

 
In OOP (Object Oriented Programming) languages the solid principle plays a desired design role to make a class flexible and easy to understand. Today we will see the Interface segregation principle.
 

Why ISP?

 
When we design/develop a class, that class should not implement any such function which not required by the customer even it those related class that we are designing or developing.
 
Let us see with an example, Develop calculator for School, Shops and for Programmers.
 
When we say calculator many things will come into mind i.e. add, sub, div, multiplication, Trigonometry functions, Calculus, etc.
 
Below is the code which full fill requirement all 3 kind of users mentioned above i.e. School, Shops and for Programmers 
  1. import math  
  2.   
  3. class Calculator():  
  4.     def add(self, *nums):          
  5.         return sum(nums)  
  6.   
  7.     def substract(self, a, b):            
  8.         return a - b if a > b else b - a  
  9.   
  10.     def multplicaton(self, nums):  
  11.         return math.prod(nums)  
  12.   
  13.     def division(self, a, b):          
  14.         return a - b if a / b else b / a  
  15.   
  16.     def sin_of(self, x):          
  17.         return math.sin(x)  
  18.   
  19.     def cos_of(self, x):  
  20.         return math.cos(x)  
  21.   
  22.     def tan_of(self, x):  
  23.         return math.tan(x)  
  24.   
  25.     def convert_hex_to_binary(self, input):  
  26.         return f"Add logic to Convert to Binary for hex input : {input}"  
  27.   
  28.     def convert_binary_to_hex(self, input):  
  29.         return f"Add logic to Convert to hex for Binary input : {input}"  
But if we observe the above code we can understand that we are giving some extra features which users may not interested in (as the user won’t use it).
 
For example, a shop holder needs only common functions like add, sub, mult, div. this user doesn’t need Trigonometry functions and HexToBinary and Vice versa function.
 
And school students need Common functions + Trigonometry functions + may need or may not need HexToBinary and Vice versa function. 
 
But as we designed and developed class including all together we don’t have an option for segregation here. We need to deliver all features to the end-user.
 
At this stage we ISP will play a key role. We can split the Calculator class into below Abstract classes (Contracts).
  1. from abc import ABC, abstractmethod  
  2.   
  3. class ICommonCalci(ABC):  
  4.     @abstractmethod  
  5.     def add(self, *nums):          
  6.         pass  
  7.  
  8.     @abstractmethod  
  9.     def substract(self, a, b):            
  10.         pass  
  11.  
  12.     @abstractmethod  
  13.     def multplicaton(self, nums):  
  14.         pass  
  15.      
  16.     @abstractmethod  
  17.     def division(self, a, b):          
  18.         pass  
  1. from abc import ABC, abstractmethod  
  2.   
  3. class IProgrammerCalci(ABC):  
  4.      
  5.     @abstractmethod  
  6.     def convert_hex_to_binary(self, input):  
  7.         pass  
  8.  
  9.     @abstractmethod  
  10.     def convert_binary_to_hex(self, input):  
  11.         pass  
  12.       
  1. from abc import ABC, abstractmethod  
  2.   
  3. class ITrigonometryCalci(ABC):  
  4.  
  5.     @abstractmethod  
  6.     def sin_of(self, x):          
  7.         pass  
  8.  
  9.     @abstractmethod  
  10.     def cos_of(self, x):  
  11.         pass  
  12.  
  13.     @abstractmethod  
  14.     def tan_of(self, x):  
  15.         pass  
And below are the 3 new classes of calculators. And if we observe them closely we implemented multilevel inheritance over here, based on user need we can deliver the particular calculator to the user. 
  1. class Common_calculator(ICommonCalci):  
  2.     def add(self, *nums):          
  3.         return sum(nums)  
  4.   
  5.     def substract(self, a, b):            
  6.         return a - b if a > b else b - a  
  7.   
  8.     def multplicaton(self, nums):  
  9.         return math.prod(nums)  
  10.   
  11.     def division(self, a, b):          
  12.         return a - b if a / b else b / a  
  1. class School_calculator(Common_calculator, ITrigonometryCalci):  
  2.     def sin_of(self, x):          
  3.         return math.sin(x)  
  4.   
  5.     def cos_of(self, x):  
  6.         return math.cos(x)  
  7.   
  8.     def tan_of(self, x):  
  9.         return math.tan(x)  
  1. class Programmer_calculator(School_calculator, IProgrammerCalci):  
  2.     def convert_hex_to_binary(self, input):  
  3.         return f"Add logic to Convert to Binary for hex input : {input}"  
  4.   
  5.     def convert_binary_to_hex(self, input):  
  6.         return f"Add logic to Convert to hex for Binary input : {input}"  
As per the above code, we can see that,
  • For Shop holders we can provide Common_calculator which implements ICommonCalci
  • For Students, we can provide School_calculator which inherits the Common_calculator, and implements ITrigonometryCalci
  • For Programmers, we can provide Programmer_calculator which inherits School_calculator, and implements IProgrammerCalci 
This way we fulfilled all user requirements. And still this class feasible to extend with new contracts for new kinds of users and for new kinds of requirements.
 

Summary

 
In this article, we learned about the interface segregation principle. I attached the source code for this article. Download and extend it for better understanding.