0% ont trouvé ce document utile (0 vote)
26 vues28 pages

Inversion of Control (Ioc) Et Dependency Injection (Di)

Transféré par

Ranim kacem
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
26 vues28 pages

Inversion of Control (Ioc) Et Dependency Injection (Di)

Transféré par

Ranim kacem
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

03

Inversion Of Control
(IoC) et Dependency
Injection (DI)
Chapitre 3 Inversion Of Control (IoC) et Dependency Injection (DI)

01 Couplage 03 Atelier 3 7

02 DI et IoC Container 05
01
Couplage
Le défi de l’extensibilité : Problématique

› Une application doit être évolutive.


› Comment être capable de répondre aux besoins futurs si on ne les connaît pas
encore ?
› Notre code doit avoir la capacité d’évoluer en impactant le moins possible l’existant.
› Et comment réussir ?
› Il nous faut réduire les dépendances au sein de notre code.
› Quel est le problème avec les dépendances ? Pourquoi faut-il les réduire ?

©MAD
Notion de couplage

› En programmation orientée objet (POO), le terme couplage est souvent utilisé pour décrire
le degré d’interdépendance entre différentes classes.
› Le couplage fort implique une dépendance élevée, tandis que le couplage faible indique
une dépendance minimale.
› Un couplage faible est généralement nécessaire car il rend le code plus modulaire,
réutilisable et facile à entretenir.

©MAD
Couplage fort

› Le couplage fort se produit lorsque les classes sont étroitement dépendantes les unes des
autres,
› Dans ce scénario, une classe crée directement des objets d’une autre classe, établissant
ainsi une connexion forte entre eux,
› Les changements dans une classe peuvent nécessiter des modifications dans l’autre, ce qui
rend le système moins flexible et moins facile à maintenir.

Lorsque la classe A est étroitement liée à la classe B, on dit que la


classe A a un couplage fort avec la classe B. La classe A ne peut
fonctionner qu’en présence de la classe B.
©MAD
Couplage fort : Exemple (1/2)

› Supposons que vous ayez une application de voyage où un Traveler (voyageur) souhaite se
déplacer en utilisant un véhicule, comme une voiture:
 Considérons la conception UML suivante :

Traveler
<use> Car
c : Car
move(): void
startJourney(): void

 L’implémentation de ce digramme a donné les deux classes suivantes :


public class Car { class Traveler {
@Override Car c = new Car();
public void move() { public void startJourney() {
[Link]("Car is moving"); [Link]();
} }
} }

 Dans notre exemple la classe Traveler lance le voyage en instanciant un objet Car pour interagir avec
lui à travers la méthode move().
©MAD
Couplage fort : Exemple (2/2)

› Le problème réside dans le couplage fort entre les objets Traveler et Car, car si l'on souhaite
utiliser un objet Bike à la place de l'objet Car, des modifications doivent être apportées à la
classe Traveler.

class Traveler {
public class Car { public class Bike { Car c = new Car();
@Override @Override Bike b = new Bike()
public void move() { public void move() { public void startJourneyWithCar() {
[Link]("Car is [Link](“Bike is moving"); [Link]();
moving"); } }
} } public void startJourneyWithBike() {
} [Link]();
}
}

› Le couplage fort est généralement considéré comme une mauvaise pratique de


conception logicielle car il rend les systèmes moins modulaires, moins flexibles et plus difficiles
à maintenir à long terme.

©MAD
Couplage faible

› Le couplage faible vise à réduire les dépendances entre les classes, rendant le système
plus flexible et plus facilement maintenable.
› Cela est réalisé en introduisant des interfaces qui définissent des méthodes communes
pour différentes implémentations.
› Avec le couplage faible, nous pourrons créer des applications fermées à la
modification et ouvertes à l’extension
 Pour obtenir un couplage faible, nous devons utiliser des interfaces.
 Considérons une classe AImpl qui implémente l’interface IA, et une
classe BImpl qui implémente l’interface IB. Si la classe AImpl est liée
à l’interface IB par association, on dit que la classe AImpl et la classe
BImpl sont faiblement couplées.
 Cela signifie que la classe AImpl peut fonctionner avec n’importe
quelle classe qui implémente l’interface IB. En fait, la classe AImpl ne
connaît que l’interface IB. Par conséquent, n’importe quelle classe
implémentant cette interface peut être associée à la classe AImpl
©MAD sans qu’il soit nécessaire de modifier quoi que ce soit dans la classe
AImpl.
Couplage faible : Exemple (1/2)

› Nouvelle conception pour notre exemple :

Traveler <<Interface>>
<use> Vehicle
-v: Vehicle
+move(): void
+getV(): Vehicle
+setV(): void
+startJourney(): void

Car Bike

+move(): void +move(): void

› Dans la classe Traveler, il n'y a pas de couplage fort avec la classe Car ou Bike.
› L’interface Vehicle a permis la mise en œuvre d'un couplage faible pour permettre le
démarrage du voyage avec n'importe quelle classe qui a implémenté cette interface.
©MAD
Couplage faible : Exemple (2/2)

// Traveler class that holds the reference to the Vehicle interface


interface Vehicle { class Traveler {
public void move(); private Vehicle v;
} public Vehicle getV() {
return v;
}
//Car class implements Vehicle interface public void setV(Vehicle v) {
class Car implements Vehicle { this.v = v;
@Override }
public void move() {
[Link]("Car is moving"); public void startJourney() {
} [Link]();
} }
}

//Bike class implements Vehicle interface // Test class for loose coupling example
class Bike implements Vehicle { public static void main(String[] args) {
@Override Traveler traveler = new Traveler();
public void move() { [Link](new Car()); // Inject Car dependency
[Link]("Bike is moving"); [Link](); // print: Car is moving
} [Link](new Bike()); // Inject Bike dependency
} [Link](); // pirnt: Bike is moving
}
Avantages :
Inconvénient :
Possibilité de changer d'implémentation
©MAD Injection des dépendances par instanciation statique
(facilement extensible)
DI &
02
IoC Container
Inversion of Control (IoC) (1/2)
› Spring utilise un système de Bean,
› Un Bean est un simple objet POJO (Plain Old Java Object), qui est instancié, assemblé
et géré par le conteneur IOC (Spring IoC Container),
› L'inversion de contrôle ( IoC : Inversion Of Control ) est un design pattern adopté par
Spring
› IoC un principe de programmation qui correspond au fait de déléguer à un framework le
flux de construction et d’appels des Beans,
› Le conteneur IOC est au cœur du framework Spring. Il permet de créer des objets
dynamiquement, et de les injecter dans d’autres objets,
› De plus, on pourra facilement modifier l’implémentation d’un objet, avec quasiment zéro
impact sur les objets qui utilisent ce dernier.
› Le conteneur IOC utilise l’injection de dépendances (Dependency Injection: DI) pour
gérer les éléments qui composent une application. (Injection par instanciation
dynamique).
©MAD
Inversion of Control (IoC) (2/2)

› Comme le montre le diagramme précédent, le conteneur Spring IoC consomme une forme
de métadonnées de configuration ; ces métadonnées de configuration représentent la façon
dont vous, en tant que développeur d’applications, demandez au conteneur Spring
d’instancier, de configurer et d’assembler les objets de votre application.

Dans Spring Boot, la configuration basée sur les annotations et la configuration XML sont
des approches permettant de définir la façon dont le conteneur IoC (Inversion of Control) doit
gérer et mettre en place des Bean dans votre application.
©MAD
Dependency Injection (DI) (1/2)

› L’injection de dépendances (DI) peut être effectuée de trois manières possibles :


 Injection de dépendances basée sur le constructeur : ce type d’injection est effectué par le
constructeur. Le constructeur a des paramètres pour initialiser directement tous les membres de la
classe.
 Injection de dépendances basée sur le setter : ce type d’injection est effectué après l’initialisation à
l’aide d’un constructeur sans argument. Les différents champs sont ensuite initialisés à l’aide de
méthodes setter.
 Injection de dépendance basée sur l’attribut: dans ce type d’injection, les dépendances sont fournies
sous la forme d’un attribut d’une classe

› Une grande puissance de Spring est l’utilisation d’interfaces pour l’injection de dépendances.
› Il est possible d’utiliser une interface, Spring se chargera alors d’utiliser l’implémentation
correcte de l’interface comme Bean.
L’injection de dépendances (DI) peut être effectuée de deux manières différentes : XML ou
annotations. Dans ce cours, seule l’approche des annotations sera abordée.
©MAD
Dependency Injection (DI) (2/2)

› Avantages de l’utilisation de DI :
 Aide dans les tests unitaires.
 L’extension de l’application devient plus facile.
 Permet d’activer le couplage faible, ce qui est important dans la programmation d’applications.
› Inconvénients de l’ID
 C’est un peu complexe à apprendre, et s’elle est surutilisé, il peut entraîner des problèmes de
gestion et d’autres problèmes.

©MAD
DI : @Autowired (1/2)

› @Autowired est une annotation qui nous permet de faire l’injection de dépendances entre
les beans de l’application (Spring IOC Container va tout faire),
› Il suffit juste d’annoter un constructeur, une propriété (attribut) ou une méthode avec cette
dernière.
› Le conteneur Spring va faire la suite(La creation du bean, le chercher et l’injecter
automatiquement…).

©MAD
DI : @Autowired (2/2)

› Exemple d’utilisation de l’annotation @Autowired :


 Nous allons créer une classe Dao et une interface IDao, suivies d’une classe ProcessData qui accédera à la
partie DAO en utilisant uniquement l’interface.

@Service
public interface IDao{ @Component Création de la classe public class ProcessData{
public class Dao implements IDao {
} // TODO……. ProcessData à l’aide de
[Link] } l’ID @Autowired
[Link]
private IDao dao;

}
[Link]

Une fois le conteneur Spring se lance, il va crée l’instance de la classe Dao et la classe ProcessData, et il
va faire l’injection de dépendance (injecter l’objet créée de la classe Dao dans la propriété de l’interface
IDao qui existe dans la classe ProcessData)

©MAD
DI : @ Qualifier (1/2)

› @Qualifier est une annotation utilisée lorsqu’on a plusieurs classes qui implémentent une
interface, et on veux faire l’injection des dépendances en utilisant cet interface.
› Elle est utilisée donc pour montrer au Conteneur Spring IOC la classe à injecter

©MAD
DI : @ Qualifier (2/2)

› Exemple d’utilisation de l’annotation @Qualifier


 Dans une seule application , on a une interface IDao qui sera implémentée par 3 classes
: DaoJdbc, DaoHibernate, DaoSpringData.

public interface IDao{ @Component


@Qualifier("jdbc")
} public class DaoJdbc implements
IDao { // TODO ….. } public class ProcessData {
[Link]
Création de la classe
ProcessData en utilisant le @Autowired
@Component principe de DI et pour spécifier @Qualifier("jdbc")
@Qualifier("hibernate") quelle classe instancier, on doit private IDao dao;
public class DaoHibernate implements IDao utiliser l’annotation Qualifier }
{ // TODO …..}
[Link] [Link]

@Component
@Qualifier("springData")
public class DaoSpringData implements
IDao { // TODO …..}
[Link]

©MAD
DI : @ Primary

› @Primary est une annotation dans Spring Boot qui indique à l'auto-configuration de Spring
quel bean doit être privilégié lorsque plusieurs candidats sont disponibles pour l'injection de
dépendances.
› Lorsqu'il existe plusieurs beans du même type et que Spring doit décider lequel injecter,
l'annotation @Primary permet de définir un bean par défaut.
› Exemple :

public class ProcessData {


@Component
@Qualifier("jdbc") Maintenant, si vous injectez IDao dans un autre
@Autowired
@Primary composant, le bean DaoJdbc sera le principal private IDao dao;
public class DaoJdbc implements candidat }
IDao { // TODO ….. }

©MAD
Exemple de DI et IoC (1/4)

› Reprenons notre exemple de l’application de voyage et ajoutons l'injection de dépendances à


l'aide de Spring Boot avec @Autowired et @Qualifier pour les classes Car et Bike

interface Vehicle {
public void move();
}

// Car class implements Vehicle interface // Bike class implements Vehicle interface
@Component @Component
@Qualifier("car") @Qualifier("bike")
public class Car implements Vehicle { public class Bike implements Vehicle {
@Override @Override
public void move() { public void move() {
[Link]("Car is moving"); [Link]("Bike is moving");
} }
} }

©MAD
Exemple de DI et IoC (2/4)
› Dans la classe Traveler, la méthode setV est // Traveler class holds the reference to the Vehicle interface
@Component
annotée avec @Autowired, ce qui signifie que public class Traveler implements CommandLineRunner {
private Vehicle v;
Spring va automatiquement injecter une public Vehicle getV() {
return v;
}
implémentation de l'interface Vehicle (dans ce // setter injection
@Autowired
cas, une instance de la classe Car) au moment public void setV(@Qualifier("car") Vehicle v) {
this.v = v;
de la création de l'objet Traveler. }
public void startJourney() {
› Lorsque l'application démarre, le bean Traveler [Link]();
}
sera créé par le conteneur Spring (IoC @Override
public void run(String... args) throws Exception {
Container), et la méthode run sera appelée, startJourney(); //print: Car is moving
}
déclenchant ainsi la methode startJourney() }

©MAD
Exemple de DI et IoC (3/4)

› Testons maintenant le bon fonctionnement de l’injection de dépendances dans notre


application :

// Test class for loose coupling example


@Component
public class TravelerTest implements CommandLineRunner {
//Method 1 : Field Injection
@Autowired
private Traveler traveler;

//Methode 2 : Constructor Injection


/* private final Traveler traveler;
public TravelerTest(Traveler traveler) {
[Link] = traveler;
}*/
@Override
public void run(String... args) throws Exception {
[Link](new Car()); // Inject Car dependency
[Link](); // print: Car is moving

[Link](new Bike()); // Inject Bike dependency


[Link](); // print: Bike is moving
}
}
©MAD
Exemple de DI et IoC (4/4)
› Pour une bonne gestion de l’injection de dépendances, @Configuration
public class AppConfig {
nous recommandons l’utilisation d’une clase de @Bean
@Qualifier("car")
configuration public Vehicle car() {
return new Car();
› La classe AppConfig permet de centraliser la }
@Bean
configuration des beans, facilitant ainsi la gestion et la @Qualifier("bike")
public Vehicle bike() {
maintenance de la configuration de l'application. return new Bike();
}
› En utilisant les méthodes annotées avec @Bean, vous @Bean
public Traveler traveler(Vehicle car) {
configurez les dépendances entre les différents Traveler traveler = new Traveler();
[Link](car);
composants de votre application. Dans cet exemple, le return traveler;
}
Traveler dépend d'une implémentation de Vehicle, et @Bean
public TravelerTest travelerTest(Traveler traveler) {
cela est géré par Spring. return new TravelerTest(traveler);
}
› Note: Pour éviter un conflit entre les beans, vous }
devez commenter toutes les annotation
@Component dans les classes précédentes
©MAD
DI : @Value

› L’annotation @Value est utilisée pour injecter des valeurs provenant de sources externes dans
un attribut ou de méthode. Il est couramment utilisé pour injecter des valeurs de propriété à
partir de fichiers de configuration ou de variables d’environnement.
› Examples:

©MAD
Annotations de déclaration des beans

› @Component: Annotation de composant générique utilisée pour déclarer un POJO en tant que
bean.
› Specialisation de @Component:
 @Service: Utilisé pour la logique métier ou la couche de service d’une application.
 @Repository: Utilisé pour l’accès aux données (DAO - Data Access Object).
 @Controller: Utilisé pour les composants de contrôleur dans un Spring Web MVC
 @RestController: Utilisé pour les composants de contrôleur dans une API REST.

› Ces annotations permettent une spécialisation basée sur le rôle et la fonctionnalité spécifiques
du composant dans l’application.
› Elles aident à organiser et à gérer les composants dans le cadre de Spring.

©MAD
03
Atelier 3

Vous aimerez peut-être aussi