Introduction
Here I am going to discuss the Open closed and Dependency inversion 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. "
Using the code
Before start technical discussion i want to answer the below questions :
What is Open closed principle ?
Answer: " software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification "
What is Dependency inversion ?
Answer:
- High-level modules should not depend on low-level modules. Both should depend on abstraction.
- Abstractions should not depend upon details. Details should depend upon abstractions.
Let's consider an example to make it better understand. Suppose I need a computer, not decided yet whether I need laptop,desktop ,tablet or other. Suppose I went to a Computer Shop and ask for desktop computer. Let's convert my requirements into code.
public class Desktop
{
public string GetComputerDescription()
{
return " You get a Desktop";
}
}
public class Laptop
{
public string GetComputerDescription()
{
return " You get a Laptop";
}
}
public class ComputerShop
{
public enum ComputerType
{
Laptop, Desktop
}
public ComputerShop()
{
}
public string GetMyComputerDescription(ComputerType cmptype)
{
var myComp = string.Empty;
if (ComputerType.Desktop == cmptype)
{
myComp = new Desktop().GetComputerDescription();
}
else if (ComputerType.Laptop == cmptype)
{
myComp = new Laptop().GetComputerDescription();
}
return myComp;
}
}
So, I ask for a desktop computer right
var computerShop = new ComputerShop();
computerShop.GetMyComputerDescription(ComputerShop.ComputerType.Desktop);
If you run the code it will execute fine and give you a output "You get a desktop ". So whats wrong ? Here we are violating the rule of OCP (Open Closed principle) and DI (Dependency inversion)
- Closed for modification ( we did violation of OCP)
- High-level modules should not depend on low-level modules. Both should depend on abstraction. (we did violation of DI)
Still confuse ? No problem i am explaining.
How we violate the modification rule ?
Yes we did it by creating the object of DeskTop and Laptop Class on GetMyComputerDescrition method. Because if a new type comes then we need to modify the function as well as class enam .
How we violate DI Principle ?
Yes we did it by creating the low level object ( DeskTop and Laptop ) on high level object (ComputerShop) . So High level modue (ComputerShop) depends on low level module (Laptop , desktop) and no abstraction here.
Now I am adding a new type (Tablet) and modify my class by violation the OCP . Look at the violated code below
public class ComputerShop
{
public enum ComputerType
{
Laptop, Desktop, Tablet }
public ComputerShop()
{
}
public string GetMyComputerDescription(ComputerType cmptype)
{
var myComp = string.Empty;
if (ComputerType.Desktop == cmptype)
{
myComp = new Desktop().GetComputer();
}
else if (ComputerType.Laptop == cmptype)
{
myComp = new Laptop().GetComputer();
} else if (ComputerType.Tablet == cmptype)
{
myComp = new Tablet().GetComputer();
}
return myComp;
}
}
Did you notice the violation ? Yes we modify the class as new type introduce, Now lets follow the OCP & DI rule and implement a new structure . If we can get the required computer without crating the objects on shop class then we can achieve our goal . Now we are going to introduce the abstraction .
public interface IComputer
{
string GetComputerDescrption();
}
public class Desktop : IComputer
{
public string GetComputerDescrption()
{
return " You get a Desktop";
}
}
public class Laptop:IComputer
{
public string GetComputerDescrption()
{
return " You get a Laptop";
}
}
public class Tablet : IComputer
{
public string GetComputerDescrption()
{
return " You get a new Tablet yahooooooooooooooooo";
}
}
public class ComputerShop
{
public string GetMyComputerDescription(IComputer cmptype)
{
var myComp = cmptype.GetComputerDescrption();
return myComp;
}
}
var computer = new ComputerShop();
computer.GetMyComputerDescription(new Tablet());
We introduce an Interface (IComputer) to remove the dependency from ComputerShop , Desktop and Laptop Class . Also now both high level and low level module depends on abstraction not on each other and
the abstraction is not depends on details so if the details change they should not affect the abstraction (satisfy DI ). Now we extend our new item (Tablet) without modify the ComputerShop class (satisfy OCP ).
Points of Interest
So the interface gives an extendability and remove dependency. Now whatever computer type comes, Shop class does not need to depend on any lower level module.
public class AnotherNewItem: IComputer
{
public string GetComputer()
{
return " You get a Another New Item Hurrayyyyyyy";
}
}
It simply gives the product we need from abstraction
public class Shop
{
public string GetMyComputer(IComputer cmptype)
{
var myComp = cmptype.GetComputer();
return myComp;
}
}
So now our code satisfy the both DI and OCP.