Dependency Inversion in Java

Begineer guide to using the power of Dependency Inversion with examples in Java.

Introduction

Dependency Inversion allows us to make low-level details depend on high-level policies, opposing the flow of control. Whenever a high-level policy changes, the low-level details must adapt. However, when the low-level details change, the high-level policies remain untouched. This is a key concept in OO and one of the main sources of it’s power.

In this post we will cover three important techniques to achieve dependency inversion – dependency injection, abstraction and adapter pattern. We will also see how these three work together to solve a real problem.

Problem

We write an application that aggregates weather information from multiple sources i.e. APIs. Our initial implementation might look like this:

This solution has serious design flaws. Firstly, our weather aggregator knows about concrete APIs it uses e.g. it has to deal with the fact that WeatherApi2 returns temperature in Fahrenheits. This means that our high-level aggregating policy is dependent on details of low-level data sources. Just look at the imports, that’s scary stuff!

Secondly, our aggregator creates concrete objects by itself. It both rises the level of coupling and violates Single Responsibility Principle. Thirdly, each new API requires us to change WeatherAggregator class. This is an Open-Closed Principle violation.

Dependency Injection

Dependency Injection is a pattern that moves the responsibility of dependencies creation outside of the object that is using them. Dependencies are passed into the object using a constructor or a bunch of setter methods. Dependency Injection can be used to enable Dependency Inversion.

Solving the creation problem

We will use Dependency Injection to enable Dependency Inversion in our code. Here’s a simple constructor solution:

This will force concrete API objects to be created outside of our aggregator and passed in during it’s creation. Please note how simple Dependency Injection can be – it doesn’t require sophisticated frameworks like Spring or Guice.

Abstraction

Abstraction is the key to Dependency Inversion. We put it between the high-level and low-level classes. High-level classes use the abstraction, while the low-level classes implement them.

It’s important to understand that the abstraction is logically coupled to the high-level class, despite the physical coupling of inheritance. Abstraction is modelled so that it serves high-level needs, which isn’t necessarily “comfortable” for low-level classes to implement. Since the flow of control still goes from high-level to low-level classes, we say that dependency opposes the flow.

This concept is very simple, but extremaly important for effective OO design. Take your time to fully understand what inversion means in this context.

Inverting the dependency

We are now ready to invert the dependency. We can do it by creating a common abstraction for our Weather APIs. It could be an interface like this:

Then, we have to make our Weather APIs implement the interface. WeatherApi2 would look like this:

Finally, we can fix our aggregator class by making it use WeatherSource:

Take a look at the imports again – concrete APIs are gone. Now it’s the WeatherSource interface that all classes are pointing towards. WeatherAggregator is dependent on an abstraction that fits it’s needs and all the APIs have to implement it. It’s the low-level API classes that are dependent on the high-level policy of returning temperature. Do you feel the power?

Also, we can now add as many APIs as we wish and WeatherAggregator will remain untouched. Pure awesomeness!

Adapter Pattern

Adapter Pattern is a design pattern that allows us to use a class via an interface it does not derive from. It is implemented in two variations – class adapter (using inheritance) and object adapter (using composition). In our example, we will use the object variation. Make sure to check te link above, if you are not familiar with the pattern.

Adapter pattern can be used to invert a dependency on a class that is not under our control e.g. comes from an external library. In such case, we make the adapter derive from our abstraction and call the desired class.

Spring Weather API

Imagine that SpringWeatherApi comes from an external library named Spring Weather and provides the temperature in Fahrenheits.

We want to use it in our aggregator, but we can’t make it implement WeatherSource directly. What we can do, is create an adapter that implements WeatherSource and internally uses SpringWeatherApi. Here’s the code:

Look what we did here. By using simple composition we protected our WeatherAggregator from being dependent on Spring Weather. You can use this technique to protect yourself from being dependent on any framework or library class. Now, it’s the library that serves you and your architecture, not the other way around. That’s a cool thing!

Bonus: Composite

By making a small change to WeatherAggregator, we could make it implement WeatherSource. This would give us a composite pattern – WeatherSource clients wouldn’t be able to tell if they are getting data from one source or twenty.

Summary

Dependency Inversion is a powerful tool for making our software more flexible. Whenever we see that our high-level code depends on low-level details, we should invert the dependency using abstractions. If the low-level code is already released (e.g. in a library), we can use the Adapter Pattern to connect it with the abstraction. Dependency Inversion often comes together with Dependency Injection – the latter facilitates the former.

About the Author Grzegorz Ziemoński

King of Tidy Java, nerd that thinks about producing perfect software all the time and proud owner of 2 cats.

follow me on:
  • Simon Gwerder

    How about showing where you instantiate the WeatherAPI’s, add them to a list and call WeatherAggregator to make the picture complete?

    • Well, this depends on application’s architecture. In my projects, I usually have a “main” component that is responsible for creating objects like that. I will describe how this works in Spring projects in my future posts.

  • Adam Ruka

    Very nice post. Congrats.

  • Tim

    Thanks for this article 🙂 it’s nice to know there are other people who understand what decent code looks like. I will be following your future blog posts 🙂

  • Hassen Ben Salem

    Thank you for this article !

  • TheMeerkat

    I can’t understand why this:

    return weatherSources
    .stream()
    .mapToDouble(WeatherSource::getTemperatureCelcius)
    .average()
    .getAsDouble();

    is better then this:

    double sum = 0;
    for (WeatherSource source : weatherSources) {
    sum += weatherSource.getTemperatureCelcious();
    }
    return sum/weartherSources.size():

    The old-style version does not allocate memory for anything, while the first creates a lot of objects, making it less efficient. And the old version is easier to read.

    • I just wanted to play with streams. This doesn’t have much to do with Dependency Inversion 🙂

    • Tim

      The difference is in the functional vs the imperative style.
      The functional style says nothing about adding numbers or how to calculate an average. It only talks about what should be done.
      The imperative way is more exhausting to the reader. Not only do you need to think about “what should this piece of code do” but also about “how do you calculate a correct average”, rounding errors, …

      • TheMeerkat

        What you have described as a “functional” is a bog-standard, 1970-s structured programming idea – you call a method to calculate an average and you don’t care how it calculates the average. Something that today everybody supposed to do in any language.
        The difference with the example in “functional style” is that it is using a third-party method to calculate an average, but to make your data to fit that method you need to jump though hoops (create stream, map, etc.) which makes that code more difficult to understand then a simple call to a simple method which internally just calculate average.

  • Alexey Mukas

    Thanks for the post, but you have put too much in one post. It is difficult to see the issues with code you are trying to solve. Some statement are too abstract and without explanation and examples.

  • Urban Fighta

    api’s are not implemantations api’s are intefaces, specs and such the “i” in api stands for interface not for implemantation. services implements apis because as you can guess they serve.

    • That’s absolutely right! The case that I was trying to make was about integrating with external APIs such as those exposed via REST or SOAP. Then, you have to code up the details of communicating with such API in your codebase. These are the details potentially worth abstracting from the business code. I think it doesn’t contradict your understanding, does it?

      • Urban Fighta

        I get your point but, nah dont be that guy!

        “public class WeatherApi2 implements WeatherSource” <— this is dead wrong WeatherSource is your contract therefore api not the implemantation and your WeatherApi2 is not a contract, it is a service which uses a contract and satisfies another one. Yes version 1 and 2 represents 2 api's for your module and therefore looks natural to call them api but they aren't.

        let me tidy up for you "public class WeatherService2 implements WeatherSource" you don't have to use word api to use api , language must be ubiquitous it should not create confusion the way to do that is respecting to original meaning of concept.

        • I get your point. Unless “WeatherApi2” is some real world name that makes sense to everyone, this name is bad. That being said, so is “WeatherService2”. It might be less confusing, but still does not carry enough information. We’re both doomed now 🙂