Click here to Skip to main content
Click here to Skip to main content

Tagged as

Understand Single Responsibility and Interface Segregation

, 3 May 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
This Article will help you to better understand the SRP (single responsibility principle) and ISP(Interface Segregation principle)

Introduction

Here I am going to discuss the Single responsibility and Interface segregation principle of SOLID . Now what does SOLID means ? SOLID is object oriented design principle , Where each letter has it own meaning

  • S-> Single responsibility
  • O-> Open Closed
  • L-> Liskov substitution   
  • I-> Interface segregation    
  • D-> Dependency inversion

According to Wikipedia the definition of SOLID is

"SOLID are guidelines that can be applied while working on software to remove code smells by causing the programmer to refactor the software's source code until it is both legible and extensible."

Background 

If you read my previous article it will be very helpful  for you to understand this one because i am going to use the same example here . So read the below article first. 

Understand Open Closed Principle and Dependecy Inversion .  

Using the code   

Before start technical discussion i want to answer the below questions:

  • What is Single Responsibility  principle?
  • Answer: " Every class should have a single responsibility, "
  • What is Interface segregation ?
  • Answer:  "No client should be forced to depend on methods it does not use"

I am going to use the example which i use on my previous article . Let's consider an example to make it better understand. Suppose I need the price of computer. I went to a Computer shop and ask for price of Laptop computer .  Let's convert my requirements into code.

public interface IComputerDescription
{
    string GetDescription();
    string GetColor();
    double GetPrice();
    double CalculatePriceAfterTax();
    
}
 
public class Desktop : IComputerDescription
{
    double desktopPrice = 110;     
    public string GetDescription()
    {
        return " You get a Desktop";
    }     
    public string GetColor()
    {
        return " Color is White";
    }
    public double GetPrice()
    {
        return desktopPrice;
    }
    public double CalculatePriceAfterTax()
    {
        return desktopPrice + desktopPrice * .20;
    }
}
public class Laptop : IComputerDescription
{
    double laptopPrice = 200;   
    public string GetDescription()
    {
        return " You get a Laptop";
    }        
    public string GetColor()
    {
        return " Color is Black and Red";
    }
    public double GetPrice()
    {
       return laptopPrice;
    }
    public double CalculatePriceAfterTax()
    {
        return laptopPrice + laptopPrice * .20;
    }
}
public class Tablet : IComputerDescription
{
    double tabletPrice = 500;    
    public string GetDescription()
    {
        return " You get a Tablet";
    }   
    public string GetColor()
    {
        return " Color is Silver";
    }
    public double GetPrice()
    {
        return tabletPrice;
    }
    public double CalculatePriceAfterTax()
    {
        return tabletPrice + tabletPrice * .20;
    }
}
 
public class GiftItem : IComputerDescription
{
    public string GetDescription()
    {
        return "Yes you get one PenDrive as gift item enjoy";
    }
    public string GetColor()
    {
        return "Choose Any color from Red Black and White";
    }
    public double GetPrice()
    {
        return 0;
    }
 
    public double CalculatePriceAfterTax()
    {
        return 0;
    }
}
 
public class Shop
{
    public string GetMyComputer(IComputerDescription cmptype)
    {
        // No matter how many types of computer comes 
        var myComp = cmptype.GetDescription(); 
        return myComp;
    }
    public string GetMyComputerPrice(IComputerDescription cmptype)
    {        
        var myCompprice = "Price is : " + cmptype.CalculatePriceAfterTax().ToString();
        return myCompprice;
    }
    public string GetAvailableColor(IComputerDescription cmptype)
    {
        var myCompcolor =  cmptype.GetColor().ToString();
        return myCompcolor;
    }
    public string WhatIsThecolorofGiftItem(IComputerDescription cmptype)
    {
        return GetAvailableColor(cmptype);        
    }
    public string IsThereAnyGiftItem(IComputerDescription gftType)
    {
        return GetMyComputer(gftType);
    }
}

So i ask for laptop price right.

var computerShop = new Shop();
computerShop.GetMyComputerPrice(new Laptop());

If you run the code it will execute fine and give you the output "Price is : 240".

What are the available colors for the laptop ? The answer is : "Color is Black and Red"  

computerShop.GetAvailableColor(new Laptop());

Then I ask again what if i buy a laptop , will i get any gift or something free item ? Again converting human language to code   

computerShop.IsThereAnyGiftItem(new GiftItem());

This will give you the output "Yes you get one PenDrive as gift item enjoy "

Normal human behavior is when we get any gift we get excited. I also become so excited an ask another question from that excitement . What are the available colors of your gift pen drive ? The answer is : "Choose Any color from Red Black and White".  

computerShop.WhatAreTheColorofGiftItem(new GiftItem());

I take the decision that i will buy a black laptop and want to take white color pen drive.Just notice the code and Wait Wait (Comes on my mind) !! (I start thinking )  Why , what happen whats wrong ? After analyzing the code i get the  answer . Nothing wrong to buy laptop and  taking pen drive . But our code  violating the rule of SRP(Single Responsibility  principle) and ISP( Interface segregation)    

Did you notice ? No, Still confuse ?  Ok No problem i will explain.    

How we violate the SRP rule?

" There should never be more than one reason for a class to change." — Robert Martin, SRP paper linked from The Principles of OOD "

Look at the functions below those are the culprits , its a price calculation logic but its in the desktop laptop and tablet class . So  if the price has changed then we need to change the classes for that and if the calculation logic  changes then we need to do it again . So we need to change the same class for two different reason , because classes have multiple responsibility ( this is the violation). 

public double CalculatePriceAfterTax()
{
   return desktopPrice+ (desktopPrice *0.2);
}
public double CalculatePriceAfterTax()
{
    return laptopPrice + (laptopPrice * 0.2);
}
public double CalculatePriceAfterTax()
{
   return tabletPrice+(tabletPrice*.20);
}

Now See how violation take place on Desktop class for SRP 

public class Desktop : IComputerDescription
{
    double desktopPrice = 130;     // Change Price (one reason)
    public string GetDescription()
    {
        return " You get a Desktop";
    }     
    public string GetColor()
    {
        return " Color is White";
    }
    public double GetPrice()
    {
        return desktopPrice;
    }
    public double CalculatePriceAfterTax()
    // Change calculation Logic (another different reason )
    {
        return desktopPrice + 
           (desktopPrice * .20)+1; // Violation of SRP
    }
}

How we violate ISP rule?  

"Clients should not be forced to depend upon interfaces that they do not use." — Robert Martin, ISP paper linked from The Principles of OOD 

Yes we did it by implementing the interface to the GiftItem. Because gift items are free no price calculation  needed but we forcefully implement it. (Violation of ISP).

public class GiftItem : IComputerDescription
{
    public string GetDescription()
    {
        return "Yes you get one PenDrive as gift item enjoy";
    }
    public string GetColor()
    {
        return " Any color from Red Black and White";
    }
    public double GetPrice()
    {
        return 0; // No Use here but forcefully implemented ------ Violation of ISP
    }
 
    public double CalculatePriceAfterTax()
    {
        return 0; // No Use here but forcefully implemented  ------ Violation of ISP
    }
}

Did you notice the violation ? Yes we modify the class for two different reason and unnecessarily implement the interface  method CalculatePriceAfterTax and GetPrice on GiftItem class, Now lets follow the SRP &  ISP rule and implement a new structure . If we can give the responsibility of calculating the price to another class and remove the unused implementation  from GiftItem class then we can achieve our goal . 

Look at the code below how we break down the interface ( this helps to implement ISP rule easily)

public interface IComputerDescription
{
    string GetDescription();
    string GetColor();
}
public interface IComputerPrice
{
    double GetPrice();
}
public interface IPriceCalculation
{
    double CalculatePriceAfterTax(IComputerPrice c);
}

Now the implementation also going to be changed right .  

public class Desktop : IComputerDescription,IComputerPrice
{
    double desktopPrice = 130;     
    public string GetDescription()
    {
        return " You get a Desktop";
    }     
    public string GetColor()
    {
        return " Color is White";
    }
    public double GetPrice()
    {
        return desktopPrice;
    }    
}
 
public class Laptop : IComputerDescription,IComputerPrice
{
    double laptopPrice = 200;   
    public string GetDescription()
    {
        return " You get a Laptop";
    }        
    public string GetColor()
    {
        return " Color is Black";
    }
    public double GetPrice()
    {
       return laptopPrice;
    }   
}
 
public class Tablet : IComputerDescription,IComputerPrice
{
    double tabletPrice = 500;    
    public string GetDescription()
    {
        return " You get a Tablet";
    }   
    public string GetColor()
    {
        return " Color is Silver";
    }
    public double GetPrice()
    {
        return tabletPrice;
    }    
}
public class GiftItem : IComputerDescription
{
    public string GetDescription()
    {
        return "Yes you get one PenDrive as gift item enjoy";
    }
    public string GetColor()
    {
        return " Any color from Red Black and White";
    }    
}
//New Class introduce to take the responsibility of calculation price
public class CalculateComputerPrice:IPriceCalculation
{
    public double CalculatePriceAfterTax(IComputerPrice c)
    {
        return c.GetPrice() + c.GetPrice() * .20;
    }
}
 
public class Shop
{
    public string GetMyComputer(IComputerDescription cmptype)
    {
        // No matter how many types of computer comes 
        var myComp = cmptype.GetDescription(); 
        return myComp;
    }
    public string GetMyComputerPrice(IPriceCalculation cmpCal, IComputerPrice cmpPrice)
    {
        var myCompprice = "Price is : " + 
                 cmpCal.CalculatePriceAfterTax(cmpPrice).ToString();
        return myCompprice;
    }
    public string GetAvailableColor(IComputerDescription cmptype)
    {
        var myCompcolor =  cmptype.GetColor().ToString();
        return myCompcolor;
    }
    public string WhatIsThecolorofGiftItem(IComputerDescription cmptype)
    {
        return GetAvailableColor(cmptype);        
    }
    public string IsThereAnyGiftItem(IComputerDescription gftType)
    {
        return GetMyComputer(gftType);
    }
}

Points of Interest  

So if i ask the same question again with our new code structure what will be the answer :

Question 1) What's the price of a laptop?  

Answer :  "Price is : 240". Same as before but different class (CalculateComputerPrice) is responsible for the calculation. So its Satisfy (SRP) 

var queryforProduct = new Laptop();
var computerShop = new Shop();
var responsibleforCalculation = new CalculateComputerPrice();
var myAnswer = computerShop.GetMyComputerPrice(responsibleforCalculation, queryforProduct);

Question 2) What are the available colors for the laptop ?  

Answer: "Color is Black and Red"  Same as before. So coe does not effected for refactor.

var myAnswer = computerShop.GetAvailableColor(queryforProduct);

Question 3) What if i buy a laptop , will i get any gift or something free item ?

Answer : "Yes you get one PenDrive as gift item enjoy " same answer but GiftItem classs remove  unused items.  So its satisfy (ISP)

public class GiftItem : IComputerDescription
{
    public string GetDescription()
    {
        return "Yes you get one PenDrive as gift item enjoy";
    }
    public string GetColor()
    {
        return "Choose Any color from Red Black and White";
    }    
}
var queryforProduct = new GiftItem();
var computerShop = new Shop();
var myAnswer = computerShop.IsThereAnyGiftItem(queryforProduct);

Question 4) What are the available colors of your gift pen drive ?

Answer: "Choose Any color from Red Black and White".   Same answer but GiftItem classs remove  unused items.  So its satisfy(ISP) 

var queryforProduct = new GiftItem();
var computerShop = new Shop();        
var myAnswer = computerShop.WhatIsThecolorofGiftItem(queryforProduct); 

So now our code satisfy the both SRP and ISP.  

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Faisal(mfrony)

Bangladesh Bangladesh
I am a Sr.Software Engineer at Brain Station -23. I have 5+ years of work experience in .Net technology. I strongly believe that before software can be reusable it first has to be usable.
 
My contact info :
 
mfrony2003@yahoo.com
mfrony2003@hotmail.com
 
LinkedIn
http://www.linkedin.com/profile/view?id=106671466&trk=tab_pro

Comments and Discussions

 
GeneralMy vote of 5 PinmemberFoyzul Karim25-May-13 19:53 
QuestionSelection of classes PinmemberMember 100373508-May-13 5:46 
The real problem here is that a Gift IS NOT a computer and is incorrect to implement IComputer, instead create IGift interface (without prices) as a better way to reinforce SRP
GeneralMy vote of 4 PinmemberKenBonny7-May-13 2:43 
GeneralRe: My vote of 4 PinmemberFaisal(mfrony)7-May-13 5:53 
QuestionCalculatePriceAfterTax Pinmembertekati685-May-13 11:22 
AnswerRe: CalculatePriceAfterTax PinmemberPaulo Zemek5-May-13 11:40 
GeneralRe: CalculatePriceAfterTax Pinmembertekati685-May-13 14:24 
GeneralRe: CalculatePriceAfterTax [modified] PinmemberPaulo Zemek5-May-13 14:26 
GeneralRe: CalculatePriceAfterTax PinmemberFaisal(mfrony)5-May-13 18:28 
QuestionIsn’t it better not to hard code the tax rate at 0.2? PinmemberGeorge Swan4-May-13 21:47 
GeneralGood Job! Very clearly and useful~ PinmemberWiStRoM4-May-13 9:09 
GeneralRe: Good Job! Very clearly and useful~ PinmemberFaisal(mfrony)4-May-13 18:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141223.1 | Last Updated 3 May 2013
Article Copyright 2013 by Faisal(mfrony)
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid