Les patrons de conception structurels en Java

  1. Patron Adaptateur

L'adaptateur sert d'intermédiaire pour rendre compatibles des interfaces incompatibles. Il existe deux variantes : l'adaptateur de classe et l'adaptateur d'objet.

Adaptateur de classe

// Interface cible
interface Cible {
    void executer();
}

// Classe à adapter
class Source {
    void operationSpecifique() {
        System.out.println("Opération spécifique de la Source");
    }
}

// Adaptateur de classe
class AdaptateurDeClasse extends Source implements Cible {
    @Override
    public void executer() {
        operationSpecifique();
    }
}

// Code client
public class Application {
    public static void main(String[] args) {
        Cible adapteur = new AdaptateurDeClasse();
        adapteur.executer();
    }
}

Adaptateur d'objet

// Interface cible
interface Cible {
    void executer();
}

// Classe à adapter
class Source {
    void operationSpecifique() {
        System.out.println("Opération spécifique de la Source");
    }
}

// Adaptateur d'objet
class AdaptateurDObjet implements Cible {
    private Source source;

    public AdaptateurDObjet(Source source) {
        this.source = source;
    }

    @Override
    public void executer() {
        source.operationSpecifique();
    }
}

// Code client
public class Application {
    public static void main(String[] args) {
        Source source = new Source();
        Cible adapteur = new AdaptateurDObjet(source);
        adapteur.executer();
    }
}

  1. Patron Pont

Ce patron sépare l'abstraction de son implémentation, permettant aux deux d'évoluer indépendamment. Il utilise une composition pour lier les deux hiérarchies.

// Interface d'implémentation
interface Implementation {
    void operationImpl();
}

// Implémentation concrète A
class ImplementationA implements Implementation {
    @Override
    public void operationImpl() {
        System.out.println("Opération de ImplementationA");
    }
}

// Implémentation concrète B
class ImplementationB implements Implementation {
    @Override
    public void operationImpl() {
        System.out.println("Opération de ImplementationB");
    }
}

// Abstraction
abstract class Abstraction {
    protected Implementation impl;

    public Abstraction(Implementation impl) {
        this.impl = impl;
    }

    public abstract void operation();
}

// Abstraction étendue
class AbstractionEtendue extends Abstraction {
    public AbstractionEtendue(Implementation impl) {
        super(impl);
    }

    @Override
    public void operation() {
        System.out.println("Opération de l'abstraction étendue");
        impl.operationImpl();
    }
}

// Code client
public class Application {
    public static void main(String[] args) {
        Implementation implA = new ImplementationA();
        Abstraction abstrA = new AbstractionEtendue(implA);
        abstrA.operation();

        Implementation implB = new ImplementationB();
        Abstraction abstrB = new AbstractionEtendue(implB);
        abstrB.operation();
    }
}

  1. Patron Composite

Il permet de traiter uniformément les objets individuels et les compositions d'objets, formant des structures arborescentes avec des nœuds feuilles et composites.

// Interface composant
interface Composant {
    void operation();
}

// Classe feuille
class Feuille implements Composant {
    private String identifiant;

    public Feuille(String identifiant) {
        this.identifiant = identifiant;
    }

    @Override
    public void operation() {
        System.out.println("Opération de la feuille " + identifiant);
    }
}

// Classe composite
class Composite implements Composant {
    private List<composant> enfants = new ArrayList<>();

    public void ajouter(Composant composant) {
        enfants.add(composant);
    }

    public void supprimer(Composant composant) {
        enfants.remove(composant);
    }

    @Override
    public void operation() {
        for (Composant composant : enfants) {
            composant.operation();
        }
    }
}

// Code client
public class Application {
    public static void main(String[] args) {
        Composant feuille1 = new Feuille("X");
        Composant feuille2 = new Feuille("Y");
        Composant feuille3 = new Feuille("Z");

        Composite compositeRacine = new Composite();
        compositeRacine.ajouter(feuille1);
        compositeRacine.ajouter(feuille2);

        Composite sousComposite = new Composite();
        sousComposite.ajouter(feuille3);
        compositeRacine.ajouter(sousComposite);

        compositeRacine.operation();
    }
}
</composant>
  1. Patron Décorateur

Il ajoute dynamiquement des responsabilités à un objet sans modifier son code. Le décorateur enveloppe l'objet original et étend son comportement.

// Interface composant
interface Boisson {
    String getDescription();
    double cout();
}

// Composant concret
class CafeSimple implements Boisson {
    @Override
    public String getDescription() {
        return "Café simple";
    }

    @Override
    public double cout() {
        return 1.0;
    }
}

// Décorateur abstrait
abstract class DecorateurBoisson implements Boisson {
    protected Boisson boissonDecoree;

    public DecorateurBoisson(Boisson boissonDecoree) {
        this.boissonDecoree = boissonDecoree;
    }

    public String getDescription() {
        return boissonDecoree.getDescription();
    }

    public double cout() {
        return boissonDecoree.cout();
    }
}

// Décorateur concret pour le lait
class DecorateurLait extends DecorateurBoisson {
    public DecorateurLait(Boisson boissonDecoree) {
        super(boissonDecoree);
    }

    @Override
    public String getDescription() {
        return boissonDecoree.getDescription() + ", Lait";
    }

    @Override
    public double cout() {
        return boissonDecoree.cout() + 0.5;
    }
}

// Code client
public class Application {
    public static void main(String[] args) {
        Boisson cafe = new CafeSimple();
        System.out.println(cafe.getDescription() + " coûte $" + cafe.cout());

        Boisson cafeLait = new DecorateurLait(cafe);
        System.out.println(cafeLait.getDescription() + " coûte $" + cafeLait.cout());
    }
}

  1. Patron Façade

Il fournit une interface simplifiée pour un ensemble di'nterfaces dans un sous-système, masquant la complexité interne et réduisant le couplage.

// Classe du sous-système A
class SousSystemeA {
    public void actionA() {
        System.out.println("Action du SousSystemeA");
    }
}

// Classe du sous-système B
class SousSystemeB {
    public void actionB() {
        System.out.println("Action du SousSystemeB");
    }
}

// Classe du sous-système C
class SousSystemeC {
    public void actionC() {
        System.out.println("Action du SousSystemeC");
    }
}

// Classe façade
class Facade {
    private SousSystemeA sousSystemeA;
    private SousSystemeB sousSystemeB;
    private SousSystemeC sousSystemeC;

    public Facade() {
        sousSystemeA = new SousSystemeA();
        sousSystemeB = new SousSystemeB();
        sousSystemeC = new SousSystemeC();
    }

    public void operationGlobale() {
        System.out.println("Opération via la façade");
        sousSystemeA.actionA();
        sousSystemeB.actionB();
        sousSystemeC.actionC();
    }
}

// Code client
public class Application {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.operationGlobale();
    }
}

  1. Patron Flyweight

Il optimise la mémoire en partageant des objets similaires. Un objet flyweight partage un état intrinsèque, tandis que l'état extrinsèque est passé lors des appels.

import java.util.Map;
import java.util.HashMap;

// Fabrique flyweight
class FabriqueFlyweight {
    private Map<string flyweight=""> pool = new HashMap<>();

    public Flyweight obtenirFlyweight(String cle) {
        Flyweight flyweight = pool.get(cle);
        if (flyweight == null) {
            flyweight = new FlyweightConcret(cle);
            pool.put(cle, flyweight);
        }
        return flyweight;
    }
}

// Interface flyweight
interface Flyweight {
    void operation();
}

// Classe flyweight concrète
class FlyweightConcret implements Flyweight {
    private String cle;

    public FlyweightConcret(String cle) {
        this.cle = cle;
    }

    @Override
    public void operation() {
        System.out.println("Opération du Flyweight " + cle);
    }
}

// Code client
public class Application {
    public static void main(String[] args) {
        FabriqueFlyweight fabrique = new FabriqueFlyweight();

        Flyweight fw1 = fabrique.obtenirFlyweight("alpha");
        fw1.operation();

        Flyweight fw2 = fabrique.obtenirFlyweight("beta");
        fw2.operation();

        Flyweight fw3 = fabrique.obtenirFlyweight("alpha");
        fw3.operation();
    }
}
</string>
  1. Patron Proxy

Il contrôle l'accès à un objet en fournissant un substitut. Le proxy peut gérer des fonctions comme l'accès distant, la protection ou la mise en cache.

// Interface sujet
interface Sujet {
    void traiterRequete();
}

// Classe sujet réelle
class SujetReel implements Sujet {
    @Override
    public void traiterRequete() {
        System.out.println("SujetReel : Traitement de la requête");
    }
}

// Classe proxy
class Proxy implements Sujet {
    private SujetReel sujetReel;

    public Proxy() {
        this.sujetReel = new SujetReel();
    }

    @Override
    public void traiterRequete() {
        System.out.println("Proxy : Journalisation de la requête");
        sujetReel.traiterRequete();
        System.out.println("Proxy : Post-traitement");
    }
}

// Code client
public class Application {
    public static void main(String[] args) {
        Proxy proxy = new Proxy();
        proxy.traiterRequete();
    }
}

Étiquettes: patrons de conception Java structures adaptation pont

Publié le 25 juin à 22h02