Understanding Dependency Injection

Nabilnazmul
3 min readOct 21, 2023

--

Today we are going to discuss about dependency injection Before diving into details we need the basics first.

What is the meaning of the word dependency in terms of object oriented programming world and what dies injection refer to?

Let’s understand dependency first.

class Car {
private Vehicle vehicle;

public Car(Vehicle vehicle) {
this.vehicle = vehicle;
}

public void startCar() {
vehicle.start();
System.out.println("Car started.");
}
}

The member variables of a class are its dependencies.

So we can say here vehicle is a dependency of Car class.and Car is dependant on vehicle…

And if you closely see the dependency is constructed through the constructor of the class.This what we mean injection.

By not constructed directly inside the class by new keyword.Rather we are injecting the dependency From another class from where we are creating object of class Car.

Let’s now understand the necessity of dependency injection...

public class AuthService {
private EmailAuthProvider emailProvider;

public AuthService() {
this.emailProvider = new EmailAuthProvider();
}

public boolean authenticate(String username, String password) {
return emailProvider.authenticate(username, password);
}
}

The above example is without dependency injection. Here the class is tightly coupled.The dependency us constructed in it’s contructor but it is not injected.

But the classes shouldn’t construct any of it’s dependencies itself.Reason?

Imagine you have another login service like google or facebook login.How can you switch your implementation?

You have to modify the code again and again which violates the ooen closed principle of Solid principle

Also you cannot test the code properly as you are unable to switch between implementations.

Here comes dependency injection comes into play.

Let’s have a look how dependency injection helps.Also how we can achieve flexibility by switching different implementation…..

public abstract class AuthProvider {
public abstract boolean authenticate(String username, String password);
}
public class EmailAuthProvider extends AuthProvider {
@Override
public boolean authenticate(String username, String password) {
// Authentication logic for email-based login
// Check the username and password
return true; // Placeholder logic for email authentication
}
}

public class GoogleAuthProvider extends AuthProvider {
@Override
public boolean authenticate(String username, String password) {
// Authentication logic for Google login
// Verify the Google credentials
return true; // Placeholder logic for Google authentication
}
}


public class FacebookAuthProvider extends AuthProvider {
@Override
public boolean authenticate(String username, String password) {
// Authentication logic for Facebook login
// Verify the Facebook credentials
return true; // Placeholder logic for Facebook authentication
}
}

Now AuthProvider is the abstract reference of AuthService class.

So it can take different implementations of AuthProvider like EmailAuthProvider, GoogleAuthProvider,FacebookAuthProvider bases on the authentication system required.

public class Main {
public static void main(String[] args) {
AuthService emailAuthService = new AuthService(new EmailAuthProvider());
AuthService googleAuthService = new AuthService(new GoogleAuthProvider());
AuthService facebookAuthService = new AuthService(new FacebookAuthProvider());

// Authenticate users with different providers
boolean emailAuth = emailAuthService.authenticate("user@email.com", "password");
boolean googleAuth = googleAuthService.authenticate("google-user", "google-password");
boolean facebookAuth = facebookAuthService.authenticate("facebook-user", "facebook-password");

System.out.println("Email Auth: " + emailAuth);
System.out.println("Google Auth: " + googleAuth);
System.out.println("Facebook Auth: " + facebookAuth);
}
}

So here we can switch different implementation class in runtime.

Thus we achieve dependency inversion principle of Solid Principles.

As we we can switch between different implementation we achieve-

1.Flexibility

2.Testability

3.Loose coupling

It facilities unit testing as we can create mock of AuthProvider for different authentication scenarios.

Also it enables loose coupling as we are able to extend our existing software without breaking the system.

That’s all for today.Hope you enjoyed it.Hit a few claps if you find it helpful…

--

--

Nabilnazmul

I am a flutter developer working in software industry for two years .I love problem solving. I would really like to share my knowledge.