Injection de dépendances en Java¶
Introduction générale¶
L’injection de dépendances (Dependency Injection – DI) est un principe visant à réduire le couplage entre classes, améliorer la testabilité et clarifier l’architecture en séparant la création des objets de leur utilisation.
DI s’inscrit dans le principe plus large d’Inversion de Contrôle (IoC).
Problème du couplage fort¶
Exemple problématique :
public class ServiceClient {
private DatabaseConnection connection;
public ServiceClient() {
this.connection = new DatabaseConnection();
}
public void doSomething() {
connection.query("SELECT * FROM clients");
}
}
Problèmes : dépendance forte, faible testabilité, difficulté de substitution, configuration figée.
Principe de l’injection de dépendances¶
La dépendance est fournie par un tiers :
public class ServiceClient {
private final DatabaseConnection connection;
public ServiceClient(DatabaseConnection connection) {
this.connection = connection;
}
public void doSomething() {
connection.query("SELECT * FROM clients");
}
}
Formes principales de DI¶
Injection par constructeur (recommandée)¶
public class ServiceClient {
private final Repository repository;
public ServiceClient(Repository repository) {
this.repository = repository;
}
}
Injection via setter¶
public class ServiceClient {
private Repository repository;
public void setRepository(Repository repository) {
this.repository = repository;
}
}
Injection par champ¶
Utilisée par certains frameworks (ex. Spring avec @Autowired).
DI et interfaces pour réduire le couplage¶
Interface :
Implémentations :
public class EmailService implements NotificationService {
public void envoyer(String msg) { System.out.println("Email: " + msg); }
}
public class SmsService implements NotificationService {
public void envoyer(String msg) { System.out.println("SMS: " + msg); }
}
Contrôleur utilisant DI :
public class NotificationController {
private final NotificationService service;
public NotificationController(NotificationService service) {
this.service = service;
}
public void notifier() {
service.envoyer("Bonjour !");
}
}
Exemple MVC utilisant DI¶
Interface vue :
Vue console :
public class ConsoleView implements View {
public void afficher(String msg) { System.out.println(msg); }
}
Contrôleur :
public class Controller {
private final Bibliotheque model;
private final View view;
public Controller(Bibliotheque model, View view) {
this.model = model;
this.view = view;
}
}
DI dans les tests unitaires¶
Mock de vue :
public class MockView implements View {
private String dernierMessage;
@Override
public void afficher(String msg) { this.dernierMessage = msg; }
public String getDernierMessage() { return dernierMessage; }
}
Test :
@Test
public void testAffichage() {
Bibliotheque model = new Bibliotheque();
MockView view = new MockView();
Controller ctrl = new Controller(model, view);
ctrl.ajouterLivre("Dune");
assertEquals("Livre ajouté", view.getDernierMessage());
}
Bonnes pratiques¶
- Favoriser DI par constructeur
- Utiliser des interfaces
- Garder les classes immuables
- Pas de logique dans les constructeurs
- DI ne remplace pas l’architecture, elle la supporte
Conclusion¶
L’injection de dépendances est un pilier du développement Java moderne.
Elle rend les systèmes modulaires, testables et évolutifs, que ce soit en Java pur, avec MVC ou au sein de frameworks comme Spring.