Inversion of Control (IoC) Principle

The IoC principle helps in designing loosely coupled classes that make them testable, maintainable and extensible.

Aaron Chu
4 min readJan 3, 2020

Inversion of Control (IoC) is a programming design principle that inverts the flow of control to achieve the following design purposes:

  • To decouple the execution of a task from implementation.
  • To focus a module on the task it is designed for.
  • To free modules from assumptions about how other systems do what they do and instead rely on contracts.
  • To prevent side effects when replacing a module.

For example, you can control when and where to execute a piece of code on your own, however, you can also register a listener to a framework and hand over the control to the framework. Then, let the framework do the job for you and call back to your listener on a specific event that happens. In other words, the flow of control is inverted from you to the framework. Sometimes, IoC is facetiously referred to as the “Hollywood Principle: Don’t call us, we’ll call you”.

For a more comprehensive understanding of IoC, imagine you are the CEO of a company and going to visit an important business partner. You can definitely drive a car yourself. In this case, you control the car. On the other hand, you can also hire a driver to drive the car for you instead. The control of the car is inverted from you to the driver now.

Travis Kalanick, former CEO of Uber

What’s the benefit of handing over the control to the driver? Well, the execution of the driving task is decoupled from implementation, you don’t need to care how exactly the driver drives the car as long as the driver can take you to the destination on time. Moreover, the driver can also be easily replaced without any impact on the mission you are mainly responsible for. With hiring the driver, you can focus on thinking of how to convince the potential partner to cooperate with you on the way to the partner’s office. After all, that’s your main responsibility as a CEO, isn’t it? The driving is not supposed to be your concern.

Invert the control of driving

Let’s take the CEO scenario mentioned above to exemplify.

In the above case, driving a car to a partner’s office isn’t the CEO’s main job to do. Thus, the CEO hires a driver to drive for him/her as below.

Now, the control of driving is inverted to a driver. However, do you notice that the CEO still controls the hire (creation) of a driver? This is also not supposed to be the CEO’s responsibility. In addition, from the code’s perspective, the Driver is the dependent object of Ceo and the Ceo is tightly coupled to it. The Ceo is difficult to be tested because the Driver instance is created inside the Ceo. You are not able to replace the Driver with a mock one when you are testing the Ceo.

Invert the control of constructing a driver

To solve the above problem, you can introduce the Dependency Injection (DI) pattern, which is one form of IoC, to invert the control of dependent object creation for this. Dependency injection involves four roles:

  • Client is dependent on the Services.
  • Service is the object to be injected to the Client.
  • Injector is responsible for constructing Service and injecting it to the Client.
  • Interface defines how the Client uses the Service.

In our case, the Client is the Ceo and Service is the Driver. As for Interface, let’s define it for Driver (Service). We create a Driver interface and there is one implementation UberDriver for now.

Regarding Injector, anyone who is responsible for constructing the Driver instance and injecting it to the Ceo is called an injector.

Types of dependency injection

Dependency injection provides at least three ways to inject a dependency:

  1. Constructor injection: the dependent objects are injected into a class through the constructor.

2. Setter injection: the dependent objects are injected into a class through a setter method.

3. Interface injection: the dependent objects are injected into a class implementing a setter interface through the defined setter method.

By applying dependency injection, Ceo is fully decoupled from Driver now and the control of constructing a driver is inverted from Ceo to Injector.

Conclusion

In this article, we introduce what’s the Inversion of Control (IoC) by giving you some examples. In the beginning, the CEO takes more responsibilities than he/she had such as driving a car. The control of driving is inverted by hiring a driver for driving the car for the CEO. The control of hiring a driver is inverted by applying Dependency Injection (DI) to inject the driver from an injector. The IoC principle helps in designing loosely coupled classes that make them testable, maintainable and extensible.

In fact, dependency injection is not the only pattern implementing the IoC. For example, the design patterns (but not limited) shown in the following figure are also the implementation of IoC.

For more information about design patterns, please refer to the following website.

--

--