Dependency Inversion Principle

Dependency Inversion Principle

As a Java programmer, you’ve likely heard about code coupling and have been told to avoid tightly coupled code. Ignorance of writing “good code” is the main reason of tightly coupled code existing in applications. As an example, creating an object of a class using the new operator results in a class being tightly coupled to another class. Such coupling appears harmless and does not disrupt small programs. But, as you move into enterprise application development, tightly coupled code can lead to serious adverse consequences.

When one class knows explicitly about the design and implementation of another class, changes to one class raise the risk of breaking the other class. Such changes can have rippling effects across the application making the application fragile. To avoid such problems, you should write “good code” that is loosely coupled, and to support this you can turn to the Dependency Inversion Principle.

The Dependency Inversion Principle represents the last “D” of the five SOLID principles of object-oriented programming. Robert C. Martin first postulated the Dependency Inversion Principle and published it in 1996. The principle states:

“A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.”

Conventional application architecture follows a top-down design approach where a high-level problem is broken into smaller parts. In other words, the high-level design is described in terms of these smaller parts. As a result, high-level modules that gets written directly depends on the smaller (low-level) modules.

What Dependency Inversion Principle says is that instead of a high-level module depending on a low-level module, both should depend on an abstraction. Let us look at it in the context of Java through this figure.

Applying Dependency Inversion Principle

In the figure above, without Dependency Inversion Principle, Object A in Package A refers Object B in Package B. With Dependency Inversion Principle, an Interface A is introduced as an abstraction in Package A. Object A now refers Interface A and Object B inherits from Interface A. What the principle has done is:

  1. Both Object A and Object B now depends on Interface A, the abstraction.
  2. It inverted the dependency that existed from Object A to Object B into Object B being dependent on the abstraction (Interface A).

Before we write code that follows the Dependency Inversion Principle, let’s examine a typical violating of the principle.

Dependency Inversion Principle Violation (Bad Example)

Consider the example of an electric switch that turns a light bulb on or off. We can model this requirement by creating two classes: ElectricPowerSwitch and LightBulb. Let’s write the LightBulb class first.

LightBulb.java

public class LightBulb {
    public void turnOn() {
        System.out.println("LightBulb: Bulb turned on...");
    }
    public void turnOff() {
        System.out.println("LightBulb: Bulb turned off...");
    }
}

In the LightBulb class above, we wrote the turnOn() and turnOff() methods to turn a bulb on and off.

Next, we will write the ElectricPowerSwitch class.

ElectricPowerSwitch.java

public class ElectricPowerSwitch {
    public LightBulb lightBulb;
    public boolean on;
    public ElectricPowerSwitch(LightBulb lightBulb) {
        this.lightBulb = lightBulb;
        this.on = false;
    }
    public boolean isOn() {
        return this.on;
    }
    public void press(){
        boolean checkOn = isOn();
        if (checkOn) {
            lightBulb.turnOff();
            this.on = false;
        } else {
            lightBulb.turnOn();
            this.on = true;
        }

    }
}

In the example above, we wrote the ElectricPowerSwitch class with a field referencing LightBulb. In the constructor, we created a LightBulb object and assigned it to the field. We then wrote a isOn() method that returns the state of ElectricPowerSwitch as a boolean value. In the press() method, based on the state, we called the turnOn() and turnOff() methods.

Our switch is now ready for use to turn on and off the light bulb. But the mistake we did is apparent. Our high-level ElectricPowerSwitch class is directly dependent on the low-level LightBulb class. if you see in the code, the LightBulb class is hardcoded in ElectricPowerSwitch. But, a switch should not be tied to a bulb. It should be able to turn on and off other appliances and devices too, say a fan, an AC, or the entire lightning system of an amusement park. Now, imagine the modifications we will require in the ElectricPowerSwitch class each time we add a new appliance or device. We can conclude that our design is flawed and we need to revisit it by following the Dependency Inversion Principle.

Following the Dependency Inversion Principle

To follow the Dependency Inversion Principle in our example, we will need an abstraction that both the ElectricPowerSwitch and LightBulb classes will depend on. But, before creating it, let’s create an interface for switches.

Switch.java

   //package guru.springframework.blog.dependencyinversionprinciple.highlevel;

public interface Switch {
    boolean isOn();
    void press();
}

We wrote an interface for switches with the isOn() and press() methods. This interface will give us the flexibility to plug in other types of switches, say a remote control switch later on, if required. Next, we will write the abstraction in the form of an interface, which we will call Switchable.

Switchable.java

   //package guru.springframework.blog.dependencyinversionprinciple.highlevel;

public interface Switchable {
    void turnOn();
    void turnOff();
}

In the example above, we wrote the Switchable interface with the turnOn() and turnoff() methods. From now on, any switchable devices in the application can implement this interface and provide their own functionality. Our ElectricPowerSwitch class will also depend on this interface, as shown below:

ElectricPowerSwitch.java

   //package guru.springframework.blog.dependencyinversionprinciple.highlevel;


public class ElectricPowerSwitch implements Switch {
    public Switchable client;
    public boolean on;
    public ElectricPowerSwitch(Switchable client) {
        this.client = client;
        this.on = false;
    }
    public boolean isOn() {
        return this.on;
    }
   public void press(){
       boolean checkOn = isOn();
       if (checkOn) {
           client.turnOff();
           this.on = false;
       } else {
             client.turnOn();
             this.on = true;
       }

   }
}

In the ElectricPowerSwitch class we implemented the Switch interface and referred the Switchable interface instead of any concrete class in a field. We then called the turnOn() and turnoff() methods on the interface, which at run time will get invoked on the object passed to the constructor. Now, we can add low-level switchable classes without worrying about modifying the ElectricPowerSwitch class. We will add two such classes: LightBulb and Fan.

LightBulb.java

   //package guru.springframework.blog.dependencyinversionprinciple.lowlevel;

import guru.springframework.blog.dependencyinversionprinciple.highlevel.Switchable;

public class LightBulb implements Switchable {
    @Override
    public void turnOn() {
        System.out.println("LightBulb: Bulb turned on...");
    }

    @Override
    public void turnOff() {
        System.out.println("LightBulb: Bulb turned off...");
    }
}

Fan.java

   //package guru.springframework.blog.dependencyinversionprinciple.lowlevel;

import guru.springframework.blog.dependencyinversionprinciple.highlevel.Switchable;

public class Fan implements Switchable {
    @Override
    public void turnOn() {
        System.out.println("Fan: Fan turned on...");
    }

    @Override
    public void turnOff() {
        System.out.println("Fan: Fan turned off...");
    }
}

In both the LightBulb and Fan classes that we wrote, we implemented the Switchable interface to provide their own functionality for turning on and off. While writing the classes, if you have missed how we arranged them in packages, notice that we kept the Switchable interface in a different package from the low-level electric device classes. Although, this did not make any difference from coding perspective, except for an import statement, by doing so we have made our intentions clear- We want the low-level classes to depend (inversely) on our abstraction. This will also help us if we later decide to release the high-level package as a public API that other applications can use for their devices. To test our example, let’s write this unit test.

ElectricPowerSwitchTest.java

   //package guru.springframework.blog.dependencyinversionprinciple.highlevel;

import guru.springframework.blog.dependencyinversionprinciple.lowlevel.Fan;
import guru.springframework.blog.dependencyinversionprinciple.lowlevel.LightBulb;
import org.junit.Test;

public class ElectricPowerSwitchTest {

    @Test
    public void testPress() throws Exception {
     Switchable switchableBulb=new LightBulb();
     Switch bulbPowerSwitch=new ElectricPowerSwitch(switchableBulb);
     bulbPowerSwitch.press();
     bulbPowerSwitch.press();

    Switchable switchableFan=new Fan();
    Switch fanPowerSwitch=new ElectricPowerSwitch(switchableFan);
    fanPowerSwitch.press();
    fanPowerSwitch.press();
    }
}

The output is:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.2.3.RELEASE)

Running guru.springframework.blog.dependencyinversionprinciple.highlevel.ElectricPowerSwitchTest
LightBulb: Bulb turned on...
LightBulb: Bulb turned off...
Fan: Fan turned on...
Fan: Fan turned off...
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.016 sec - in guru.springframework.blog.dependencyinversionprinciple.highlevel.ElectricPowerSwitchTest

Summary of the Dependency Inversion Principle

Robert Martin equated the Dependency Inversion Principle, as a first-class combination of the Open Closed Principle and the Liskov Substitution Principle, and found it important enough to give its own name. While using the Dependency Inversion Principle comes with the overhead of writing additional code, the advantages that it provides outweigh the extra effort. Therefore, from now whenever you start writing code, consider the possibility of dependencies breaking your code, and if so, add abstractions to make your code resilient to changes.

Dependency Inversion Principle

 

Dependency Inversion Principle and the Spring Framework

You may think the Dependency Inversion Principle is related to Dependency Injection as it applies to the Spring Framework, and you would be correct. Uncle Bob Martin coined this concept of Dependency Inversion before Martin Fowler coined the term Dependency Injection. The two concepts are highly related. Dependency Inversion is more focused on the structure of your code, its focus is keeping your code loosely coupled. On the other hand, Dependency Injection is how the code functionally works. When programming with the Spring Framework, Spring is using Dependency Injection to assemble your application. Dependency Inversion is what decouples your code so Spring can use Dependency Injection at run time.

22 comments on “Dependency Inversion Principle

  1. November 5, 2015 at 11:28 am

    Very interesting as always. Thank you

    Reply
  2. November 5, 2015 at 11:32 am

    Thanks!

    Reply
  3. August 10, 2016 at 12:54 am

    really helpful ! thanks 😀

    Reply
  4. March 14, 2017 at 9:00 am

    Good one!

    Reply
  5. April 18, 2017 at 1:07 am

    Really a good example!! Thanks!

    Reply
  6. August 4, 2017 at 7:47 am

    Very Good Explanation on ‘Dependency Inversion’ principle. Thanks much.

    Reply
  7. November 4, 2018 at 6:29 pm

    Now, I understood the DIP. Thank you!

    Reply
  8. November 29, 2018 at 1:48 pm

    Good Example

    Reply
  9. February 15, 2019 at 5:04 am

    Very clear, and help me understand easily. Thanks you so much!

    Reply
  10. February 26, 2019 at 2:13 pm

    Thanks for sharing!
    One thing I felt a bit confusing is the term “High level” package and “Lowlevel” package.

    Highlevel package (code) usually depends on lowlevel code package right? So in low level code package, how you can refer to/inherit Switchable interface defined in highlevel code package? Highlevel code isn’t accessable from lowlevel right?

    Reply
  11. May 8, 2019 at 12:47 pm

    Good example Thanks

    Reply
  12. August 22, 2019 at 11:17 pm

    Very nice and clear explanation .

    Than you so much.

    #Amol

    Reply
  13. November 20, 2019 at 2:38 pm

    Very nice!!
    Is “void perss()” method not switchable property? It is an action like turnOn & turnOff…
    Thanks.

    Reply
  14. February 25, 2020 at 11:55 pm

    This post made me to bookmark this site <3

    Reply
  15. March 18, 2020 at 8:32 am

    Sorry but your example is wrong. In the ElectricPowerSwitch class you are not creating a LightBulb , you are passing it as a parameter to the constructor. Therefore you are already using dependency injection and there is not tight coupling there.

    Reply
    • May 22, 2020 at 4:55 pm

      ofcourse, they don’t create obj of LightBuld class in ElectricPowerSwitch, but ElectricPowerSwitch accept only the obj of LightBuld. and that’s called dependancy.

      Reply
  16. May 22, 2020 at 4:49 pm

    It’s magic……

    Reply
  17. August 28, 2020 at 12:10 pm

    Terrific example. Very well explained, as always.

    Reply
  18. September 8, 2020 at 2:02 am

    Fantasic…Thanks!!

    Reply
  19. March 29, 2021 at 4:51 am

    Hi, i was trying to make the difference between OCP and DIP and understand well the point of focus of every principle.
    OCP focus on building our classes so that we are not required to modify them when a new requirement arise, instead we should be able to add new feature while keeping our existing code unmodified.
    DIP focus on inverting the dependency between the higher module and lower to module to abstraction to have a loosely coupled implementations.
    But when it come to the implementation part of the two principle, i always see the same implementations.
    DIP can be considered as software architecture principle? as it will affect most of our implementations

    Reply
  20. April 15, 2021 at 10:08 am

    Interesting article and nice examples to prove the working of DI.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.