Vous êtes sur la page 1sur 8

Les Patrons de conception

I. Définition
Un patron de conception (Design Pattern) est une solution à un problème récurrent dans un
contexte donné. On peut considérer un patron de conception comme une formalisation de
bonnes pratiques, ce qui signifie qu'on privilégie les solutions éprouvées.

Les patrons de conception suivent un format particulier :


_ Une description du problème avec un exemple concret et une solution qui lui est spécifique
_ Un résumé des choses à considérer pour formuler une solution générale
_ La solution générale
_ Les conséquences positives et négatives de l’utilisation de la solution
_ Une liste des patrons qui sont liés

II. Différentes catégories de patrons


3 catégories de patrons :
- Création : concerne le processus de création des objets
- Structure : lié à la composition des classes ou objets
- Comportement : caractérise les façons dont les classes ou les objets interagissent ou
distribuent les responsabilités.

Création

- Fabrique abstraite (Abstract Factory)


- Monteur (Builder)
- Fabrique (Factory Method)
- Prototype (Prototype)
- Singleton (Singleton)

Structure

- Adaptateur (Adapter)
- Pont (Bridge)
- Objet composite (Composite)
- Décorateur (Decorator)
- Façade (Facade)
- Poids-mouche ou poids-plume (Flyweight)
- Proxy (Proxy)

Comportement

- Chaîne de responsabilité (Chain of responsibility)


- Commande (Command)
- Interpréteur (Interpreter)
- Itérateur (Iterator)

1
- Médiateur (Mediator)
- Memento (Memento)
- Observateur (Observer)
- État (State)
- Stratégie (Strategy)
- Patron de méthode (Template Method)
- Visiteur (Visitor)
……….

1. Singleton
Garantit qu'une classe n'a qu'une et une seule instance, tous les objets qui utilisent une
instance de cette classe, utilisent la même instance

Singleton S'assure de l'unicité d'une instance de classe et évidemment le moyen d'accéder à


cette instance unique.

Exemples :
Gestion centralisée d’une ressource :
_ Interne : un objet qui est un compteur « global »
_ Externe : un objet qui gère la réutilisation d’une connexion à une base de données
Classes qui ne devraient avoir qu’une seule instance à la fois :
_ Horloge du système
_ Fenêtre principale d’une application
_ Générateur de nombre aléatoire (random number generator)

Code en Java :

public class Singleton {


private static Singleton instance;
private int i;
private Singleton(){
System.out.println("Construction du Singleton");
}
public static synchronized Singleton getInstance(){
if (instance == null)
instance = new Singleton();
return instance;
}

public void setValue(int value){


i = value;
}

public int getValue(){


return i;
}

public static void main(String[] args) {


Singleton s = Singleton.getInstance();
System.out.println("La valeur de i est " + s.getValue());
Singleton s2 = Singleton.getInstance();
System.out.println("La valeur de i est " + s2.getValue());
// Changement de la valeur du Singleton

2
s.setValue(20);
System.out.println("La valeur de i est " + s.getValue());
System.out.println("La valeur de i est " + s2.getValue());
}
}

2. Factory
Une fabrique de création (ou factory) est une classe qui n'a pour rôle que de construire des
objets. Cette classe utilise des interfaces ou des classes abstraites pour masquer l'origine des
objets.

public class FabriqueAnimal {

Animal getAnimal(String typeAnimal) throws ExceptionCreation {


Animal animal;
if("chat".equals(typeAnimal)) {
animal = new Chat();
} else if("chien".equals(typeAnimal)) {
animal = new Chien();
} else {
throw new ExceptionCreation("Impossible de créer un " + typeAnimal);
}
return animal:
}

//CTRL + SHIFT + O pour générer les imports


public class DAOFactory {
protected static final Connection conn = Connection.getInstance();

/**
* Retourne un objet Classe interagissant avec la BDD
* @return DAO
*/
public static DAO getClasseDAO(){
return new ClasseDAO(conn);
}
/**
* Retourne un objet Professeur interagissant avec la BDD

3
* @return DAO
*/
public static DAO getProfesseurDAO(){
return new ProfesseurDAO(conn);
}
/**
* Retourne un objet Eleve interagissant avec la BDD
* @return DAO
*/
public static DAO getEleveDAO(){
return new EleveDAO(conn);
}
/**
* Retourne un objet Matiere interagissant avec la BDD
* @return DAO
*/
public static DAO getMatiereDAO(){
return new MatiereDAO(conn);
}
}

3. Injection de dépendance :
Le patron de conception Java Injection de dépendance nous permet de supprimer les
dépendances codées en dur et de rendre notre application faiblement couplée, extensible et
maintenable.

Avantages de l'injection de dépendance Java :


 Séparation des préoccupations
 Réduction du code de la chaudière dans les classes d'application car tout le travail
d'initialisation des dépendances est géré par le composant injecteur
 Les composants configurables rendent l'application facilement extensible
 Les tests unitaires sont faciles avec des objets fictifs

Les Inconvénients de l'injection de dépendance Java


 En cas de sur-utilisation, cela peut entraîner des problèmes de maintenance car les
effets des modifications sont connus à l'exécution.
 L'injection de dépendances dans Java masque les dépendances de classe de service qui
peuvent entraîner des erreurs d'exécution qui auraient été détectées au moment de la
compilation.

Code java sans mécanisme d’injection:

package ma.fstt.wdi;

public class CashPaymentService {

public void pay(Product product) {

System.out.println("Payed with cash");

}
}

4
package ma.fstt.wdi;

import java.util.ArrayList;
import java.util.List;

public class Cart {

private List<Product> productList = new ArrayList<Product> ();

private CashPaymentService paymentService = new CashPaymentService();

public void addProductToCart(Product product) {

productList.add(product);

public void buy() {

productList.stream().forEach(paymentService::pay);

public static void main(String[] args) {

Cart cart = new Cart();


cart.addProductToCart(new Product());
cart.addProductToCart(new Product());

cart.buy();

}
}

package ma.fstt.wdi;

public class Product {

Ce code marche. Mais pourquoi le la calss Cart devrait-il être responsable de la


création du service CashPaymentService?

Le Class Cart est étroitement couplé à l'objet CashPaymentService, ce qui pose


plusieurs problèmes. Que faire si nous voulons utiliser un autre service de paiement?

Si on veut ajouter un service pour payer avec une carte de crédit. Dans ce cas, nous
devrons modifier l’implémentation de l’objet Cart pour utiliser un autre service de
paiement - et ce n’est pas la responsabilité de Cart.

L’objet Cart doit faire exactement ce qu’il est censé faire. Il contient une liste de
produits et propose une méthode pour les acheter.

Le service de paiement est une dépendance externe ici. Ce service est utilisé par le
panier, mais il ne lui incombe pas de le créer. Le panier devrait juste recevoir cette
dépendance.

5
Il existe plusieurs façons de procéder, pour résoudre ce problème, généralement en
utilise le patron de conception injection des dépendances selon 3 méthodes : par
constructeur, par accesseur « gets /sets », ou bien par interfaces.

Code java avec mécanisme d’injection par constructeur:

package ma.fstt.di;

public interface PaymentService {


void pay(Product product);
}

package ma.fstt.di;

public class CardPayementService implements PaymentService{

@Override
public void pay(Product product) {
System.out.println("Payed with card");
}

package ma.fstt.di;

public class CashPaymentService implements PaymentService{

@Override
public void pay(Product product) {
System.out.println("Payed with cash");
}

package ma.fstt.di;

public class CheckPayementService implements PaymentService {

@Override
public void pay(Product product) {
System.out.println("Payed with check");
}

package ma.fstt.di;

public class PaymentServiceFactory {

public PaymentService getPaymentService(String paymentType) {

if (paymentType == null) {

return null;

6
if (paymentType.equalsIgnoreCase("CASH")) {

return new CashPaymentService();

if (paymentType.equalsIgnoreCase("CARD")) {

return new CardPayementService();

if (paymentType.equalsIgnoreCase("CHECK")) {

return new CheckPayementService();

return null;

}
}

package ma.fstt.di;

import java.util.ArrayList;
import java.util.List;

public class Cart {

private List<Product> productList = new ArrayList<> ();

private PaymentService paymentService;

public Cart(PaymentService paymentService) {

this.paymentService = paymentService;

public void addProductToCart(Product product) {

productList.add(product);

public void buy() {

productList.stream().forEach(paymentService::pay);

public static void main(String[] args) {

Cart cart = new Cart( new


PaymentServiceFactory().getPaymentService("CARD"));
cart.addProductToCart(new Product());
cart.addProductToCart(new Product());

7
cart.buy();

Note :
IoC « Inversion of Control » est un terme générique signifiant plutôt que d'avoir l’application,
qui appelle les méthodes dans un Framework, c’est le Framework qui se chargera d’appeler
les implémentations fournies par l'application.

DI « Dependency Injection » est une forme d'IoC, où les implémentations sont transmises à
un objet via des recherches de constructeurs / setters / services, sur lesquelles l'objet "dépend"
afin de se comporter correctement.

Vous aimerez peut-être aussi