Junior
What is dependency injection and what benefits does it bring?
sobes.tech AI
Answer from AI
Dependency Injection (DI) is a design pattern where components receive dependencies from outside rather than creating them themselves. It is one of the principles of Inversion of Control (IoC).
Benefits of DI:
- Improved testability: Easier to substitute mocks/stubs for dependencies during unit testing.
- Loose Coupling: Components depend less on specific implementations of dependencies.
- Increased flexibility and extensibility: Easily change dependency implementations without modifying the main code of the component.
- Improved readability and maintainability: Clearly shows what dependencies a component requires.
Example without DI vs with DI:
Without DI:
// Class that creates a dependency inside itself
public class ServiceA {
private DatabaseConnection dbConnection;
public ServiceA() {
// Strong coupling: explicitly creating a specific implementation
this.dbConnection = new OracleConnection();
}
public void doSomething() {
dbConnection.connect();
// ...
}
}
With DI (via constructor):
// Dependency interface
public interface DatabaseConnection {
void connect();
void disconnect();
}
// Different implementations
public class OracleConnection implements DatabaseConnection {
@Override
public void connect() {
System.out.println("Connecting to Oracle...");
}
@Override
public void disconnect() {
System.out.println("Disconnecting from Oracle...");
}
}
public class MySQLConnection implements DatabaseConnection {
@Override
public void connect() {
System.out.println("Connecting to MySQL...");
}
@Override
public void disconnect() {
System.out.println("Disconnecting from MySQL...");
}
}
// Class receiving dependency from outside
public class ServiceB {
private DatabaseConnection dbConnection;
// Dependency injection via constructor
public ServiceB(DatabaseConnection dbConnection) {
this.dbConnection = dbConnection;
}
public void doSomething() {
dbConnection.connect();
// ...
}
public void setDbConnection(DatabaseConnection dbConnection) {
this.dbConnection = dbConnection;
}
}
// Code performing injection (configuration)
public class Application {
public static void main(String[] args) {
// Create dependency
DatabaseConnection connection = new MySQLConnection();
// Inject dependency into ServiceB
ServiceB service = new ServiceB(connection);
service.doSomething();
// Or change dependency without modifying ServiceB
DatabaseConnection anotherConnection = new OracleConnection();
ServiceB anotherService = new ServiceB(anotherConnection);
anotherService.doSomething();
}
}
Methods of injection:
- Constructor Injection: Dependencies are provided via the class constructor. Preferred for mandatory dependencies.
- Setter Injection: Dependencies are provided via setter methods. Suitable for optional dependencies.
- Field Injection: Dependencies are injected directly into class fields (commonly used with frameworks, requires reflection). Not recommended without DI frameworks due to testing complexity and hidden dependencies.