4 min read

Inversion of Control

August 15, 2020

Inversion of Control can be quite confusing to understand and hard to explain. Inversion of Control(IoC) helps to write pluggable code that needs less refactoring. What do I mean by that? Let’s dive through.

To keep this post within the context of this site, I’ll limit the examples only to Java. But the concept of IoC by itself is not limited to a single programming language.

Applications without IoC

Let’s take an example. In an object-oriented programming environment, An object A may need another object B’s functionality to run. So it is obvious that somewhere in the Object A’s logic, Object B is created. This is also known as tight-coupling. Let’s see this below example,

package com.springhow.examples.beans;

public interface Fruit {

    String juice();
}
import com.springhow.examples.beans.Fruit;

public class Apple implements Fruit {

    @Override
    public String juice() {
        return "Here is Apple Juice";
    }
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Juicer {
    private static final Logger log = LoggerFactory.getLogger(Juicer.class);

    public void extractJuice(Fruit fruit) {
        String juice = fruit.juice();
        logger.info(juice);
    }
}
import com.springhow.examples.beans.Fruit;
import com.springhow.examples.beans.Juicer;
import com.springhow.examples.beans.impl.Apple;

public class NotAnIoCApplication {

    public static void main(String[] args) {
        Juicer juicer = new Juicer();
        Fruit fruit = new Apple();
        juicer.extractJuice(fruit);
    }
}

This will print

19:17:57.178 [main] INFO com.springhow.examples.beans.Juicer - Here is Apple Juice

In this example, an object of Apple is created by us and was given to Juicer object. You may wonder what is wrong with this approach. But let’s just take a few steps back.

If You want to use another Fruit object, Say Orange. Then you need to change the program. At least the line Fruit fruit = new Apple();. This means you are making it difficult for anyone else to use your program.

This what I call as bad code. Because you are the one who is plugging in all the components. The application code control HOW, WHEN and WHAT Fruit object is created.

To make this program work with different Fruit without refactoring, you need a concept called Inversion Of Control.

Control means something else

Imagine country A get’s its oil supply from Country B. Here we can say that Country B has control over A because A is dependent on B’s supplies. If somehow A can easily switch between different countries for its supply, A can avoid B’s control entirely.

This is what control in Inversion of Control really means. It is about removing dependencies. We will see this with an example.

An Attempt to de-couple

The word inversion is a confusing term because it is relative to how you see it. Inversion of control is a concept of freedom. It helps to decouple components and make them less dependent on each other.

Check this below example.

fruit.class.name=com.springhow.examples.beans.impl.Orange
import com.springhow.examples.beans.Fruit;
import com.springhow.examples.beans.Juicer;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class SimpleIoCApplication {

    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        InputStream inputStream
                = SimpleIoCApplication.class.getResourceAsStream("/config.properties");
        properties.load(inputStream);
        Juicer juicer = new Juicer();
        Class<?> fruitClass
                = Class.forName(properties.getProperty("fruit.class.name"));
        Fruit fruit = (Fruit) fruitClass.newInstance();
        juicer.extractJuice(fruit);
    }
}

We introduced a new config.properties and added a little Java’s Reflection magic, And now we have an inversion of control. This will print output related to Orange as we configured in the properties.

19:07:49.116 [main] INFO com.springhow.examples.beans.Juicer - Here is Orange Juice

Once this program is compiled and shipped, you don’t need to make any refactoring to the program for every other Fruit implementation.

Just change the properties file and add a new Fruit implementation to the classpath and you are good to go. This is one form of inversion of control.

You may argue that the application created object using fruitClass.newInstance(). But the application never knew which type of Fruit is created.

The right way to Inversion of Control

The above implementation is called IoC by configuration files. And it is, not a scalable solution. There are good design patterns that help in achieving IoC. Some of them are listed below.

  • Dependency Injection
  • Service locator pattern
  • Pico Containers
  • Template method pattern
  • Adapter pattern

Try to read about these if you are interested. We will focus more on Dependency injection in upcoming chapters.

Raja Anbazhagan

About the author

Raja is a Software Engineer with over 7 years of experience in working with Enterprise Java applications. Lately, He is focused in cloud-based Java applications and serverless technologies. He spends his spare time in stackoverflow.

Browse Categories