Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Understand Open Closed Principle and Dependency Inversion

4.72/5 (26 votes)
5 May 2013CPOL3 min read 41.9K  
This article will help you better understand OCP and DI.

Introduction

Here, I am going to discuss the Open closed and Dependency inversion principle of S<code>OLID . Now what does SOLID mean? SOLID is an 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 with the technical discussion, I would like 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 understood. Suppose I need a computer, not decided yet whether I need a laptop, desktop, tablet or other. Suppose I went to a Computer Shop and ask for a desktop computer. Let's convert my requirements into code.

C#
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?

C#
var computerShop = new ComputerShop();
computerShop.GetMyComputerDescription(ComputerShop.ComputerType.Desktop);

If you run the code, it will execute fine and give you an output "You get a Desktop". So what's 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 confused? No problem, I am explaining.

How do we violate the modification rule?

Yes, we did it by creating the object of Desktop and Laptop Class on GetMyComputerDescription method. Because if a new type comes, then we need to modify the function as well as class enam.

How do we violate the DI Principle?

Yes, we did it by creating the low level object (Desktop and Laptop) on high level object (ComputerShop). So High level module (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 of the OCP. Look at the violated code below:

C#
public class ComputerShop
{
    public enum ComputerType
    {
        Laptop, Desktop, Tablet  // Violation of OCP
    }
 
    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();
        }                                         // Violation of OCP
        else if (ComputerType.Tablet == cmptype)
        {
            myComp = new Tablet().GetComputer();
        }
        return myComp;
    }
} 

Did you notice the violation? Yes, we modify the class as new type introduced. Now let's follow the OCP & DI rule and implement a new structure. If we can get the required computer without creating the objects on shop class, then we can achieve our goal. Now we are going to introduce the abstraction.

C#
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)
    {
        // No matter how many types of computer comes 
        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 does not depend on details, so if the details change, they should not affect the abstraction (satisfy DI). Now we extend our new item (Tablet) without modifying the ComputerShop class (satisfy OCP).

Points of Interest

So the interface gives an extendability and removes dependency. Now whatever computer type comes, Shop class does not need to depend on any lower level module.

C#
public class AnotherNewItem: IComputer
{
    public string GetComputer()
    {
        return " You get a Another New Item Hurrayyyyyyy";
    }
}

It simply gives the product we need from abstraction:

C#
public class Shop
{   
    public string GetMyComputer(IComputer cmptype)
    {
        // No matter how many types of computer comes 
        var myComp = cmptype.GetComputer();
        return myComp;
    }
}

So now our code satisfies both DI and OCP.

License

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