Inversion of Control(IoC)

Devaraju Boddu
3 min readSep 17, 2023
SOLID: Inversion of Control (IoC)

What is Inversion of Control (IoC)

Inversion of Control (IoC) is a software design principle that promotes the decoupling of dependencies in a system, leading to more modular, maintainable, and testable code. IoC is also known as the Hollywood Principle, due to its motto: “Don’t call us; we’ll call you.” This article will discuss the concept of IoC and demonstrate how to implement it.

Understanding Inversion of Control

In a traditional software design, components directly call other components or create instances of dependencies, leading to a tightly coupled system. This tight coupling can make it challenging to modify, maintain, and test the application.

Inversion of Control addresses this issue by inverting the control flow, such that the dependencies are provided to a component, rather than the component creating or acquiring them. This results in a more modular and decoupled system, which is easier to maintain and test.

Implementing Inversion of Control

There are various ways to achieve IoC in a Java application, such as using dependency injection, service locators, or IoC containers. In this article, we’ll focus on dependency injection as a way to demonstrate IoC.

Dependency Injection(DI)

Dependency Injection (DI) is a technique to achieve IoC by providing dependencies to a component through its constructor, properties, or methods. It allows for better separation of concerns and makes testing easier by enabling the substitution of dependencies with test doubles.

Let’s consider an example where a Notification class is responsible for sending notifications via email or SMS.

Without IoC:

public class EmailService {
public void sendEmail(String to, String message) {
// Code to send an email
}
}
public class SmsService {
public void sendSms(String to, String message) {
// Code to send an sms
}
}
public class Notification {
private EmailService emailService;
private SmsService smsService;

public Notification() {
this.emailService = new EmailService();
this.smsService = new SmsService();
}

public void sendNotification(String to, String message) {
emailService.sendEmail(to, message);
smsService.sendSms(to, message);
}
}

In the above code, the Notification class directly creates instances of EmailService and SmsService, making it tightly coupled to those implementations. This tight coupling makes it difficult to modify, maintain, or test the Notification class.

Applying IoC using Dependency Injection:

public class Notification {
private final EmailService emailService;
private final SmsService smsService;

public Notification(EmailService emailService, SmsService smsService) {
this.emailService = emailService;
this.smsService = smsService;
}

public void sendNotification(String to, String message) {
emailService.sendEmail(to, message);
smsService.sendSms(to, message);
}
}

By applying IoC through dependency injection, we’ve decoupled the Notification class from the specific implementations of EmailService and SmsService. Now, the Notification class no longer needs to know how to create these services, and we can easily substitute them with alternative implementations or test doubles.

Real-World Use Cases for Inversion of Control

Inversion of Control can be applied to various real-world scenarios to improve the design of an application. Some common use cases include:

Database access: Decoupling components from specific database implementations allows for easy switching between different database systems or connection strategies.

Third-party services: By decoupling components from specific third-party service implementations, it becomes easier to switch between providers or adapt to API changes.

Logging and error handling: IoC can be used to decouple components from specific logging or error handling strategies, allowing for more flexible and configurable logging/error handling in an application.

Happy Learning… :)

--

--

Devaraju Boddu

Technical Consultant | Ruby On Rails | Java | Spring Boot | AWS