En génie logiciel, adaptateur (ou wrapper[1]) est un patron de conception (design pattern) de type structure (structural). Il permet de convertir l'interface d'une classe en une autre interface que le client attend.

L’adaptateur fait fonctionner ensemble des classes qui n'auraient pas pu fonctionner sans lui, à cause d'une incompatibilité d'interfaces[2].

Applicabilité

modifier

Il permet d'intégrer une classe à ne pas modifier[3], par exemple :

  • une API tiers convient au besoin fonctionnel, mais la signature de ses méthodes ne convient pas ;
  • l'utilisation d'anciennes classes doit être normalisée, sans pour autant en reprendre tout le code.

Un objet adaptateur sert de liaison entre les objets manipulés et un programme les utilisant, permettant la communication entre classes. Il est utilisé pour convertir l'interface d'un objet vers une autre interface, attendue par le client pour utiliser l'objet en question.

Structure

modifier
 
Schéma UML du motif de conception adaptateur.
  • IEmployee : définit l'interface métier utilisée par le employee.
  • employee : travaille avec des objets utilisant l'interface IEmployee.
  • EmployeeManager : définit une interface existante devant être adaptée.
  • employeeAdapter : fait correspondre l'interface de Adapté à l'interface IEmployee.

Mise en œuvre

modifier

Exemple en C++

modifier

Un adaptateur pour faire un carré aux coins ronds. Le code est en C++.

class Carre{
  public:
    Carre();
    virtual dessineCarre();
    virtual Coordonnees *getQuatreCoins();
};

class Cercle{
  public:
    Cercle();
    virtual dessineCercle();
    virtual void setArc1(Coordonnees *c1);
    virtual void setArc2(Coordonnees *c2);
    virtual void setArc3(Coordonnees *c3);
    virtual void setArc4(Coordonnees *c4);
    virtual Coordonnees *getCoordonneesArc();
};

class CarreCoinsRondAdaptateur: public Carre, private Cercle{
  public:
    CarreCoinsRondAdaptateur();
    virtual void dessineCarre(){
       setArc1(new Coordonnees(0,0));
       setArc2(new Coordonnees(4,0));
       setArc3(new Coordonnees(4,4));
       setArc4(new Coordonnees(0,4));
       // Fonction qui dessine les lignes entre les arcs
       dessineCercle();
    }
    virtual Coordonnees *getQuatreCoins(){
       return getCoordonneesArc();
    }
};

Exemple en C♯

modifier

En C♯ :

/// <summary> la signature "IDeveloppeur" utilisée par le client </summary>
public interface IDeveloppeur {
    /// <summary>  Requete </summary>
    string EcrireCode();
}

/// <summary> concrétisation normale de IDeveloppeur par une classe </summary>
class DeveloppeurLambda : IDeveloppeur {
    public string EcrireCode() { 
        return "main = putStrLn \"Algorithme codé\""; 
    }
}

/// <summary> Adapté qui n'a pas la signature IDeveloppeur </summary>
class Architecte {
    public string EcrireAlgorithme() { 
        return "Algorithme";
    }
}

/// <summary> Adaptateur qui encapsule un objet qui n'a pas la bonne signature</summary>
class Adaptateur : IDeveloppeur {
    Architecte _adapté;
    public Adaptateur (Architecte adapté) {
        _adapté = adapté;
    }
    public string EcrireCode() {
        string algorithme = _adapté.EcrireAlgorithme();
        return string.Format("let main() = printfn \"{0} codé\"", algorithme);
    }
}

//___________________________________________________________________
// Mise en œuvre

/// <summary> Client qui n'utilise que les objets qui respectent la signature </summary>
class Client {
    void Utiliser(IDeveloppeur cible) {
        string code = cible.EcrireCode();
        Console.WriteLine(code);
    }
    static void Main() {
        var client = new Client();

        IDeveloppeur cible1 = new DeveloppeurLambda();
        client.Utiliser(cible1);

        var adapté = new Architecte();
        IDeveloppeur cible2 = new Adaptateur(adapté);
        client.Utiliser(cible2);
    }
}

Exemple en PHP

modifier

Exemple d'un adaptateur permettant d'obtenir la description d'un véhicule en PHP :

<?php
/**
 * L'interface d'un adapteur de type véhicule
 */
interface VehicleAdapterInterface
{
    // permet d'avoir une description d'un véhicule
    public function describe() : string;
}

/**
 * L'interface d'une automobile
 */
interface CarInterface
{
    // getter de la marque
    public function getBrand() : string;
    
    // getter du modèle
    public function getModel() : string;
    
    // getter de la version
    public function getVersion() : string;
}

/**
 * L'interface d'un vélo
 */
interface BikeInterface
{
    // getter de la marque
    public function getBrand() : string;
    
    // getter du modèle
    public function getModel() : string;
}


/**
 * Classe Car implémentant la CarInterface
 */
class Car implements CarInterface 
{
    public function __construct(
        private string $brand,
        private string $model,
        private string $version,
    ) {}
      
    public function getBrand() : string 
    {
        return $this->brand;
    }

    public function getModel() : string
    {
        return $this->model;
    }

    public function getVersion() : string
    {
        return $this->version;
    }
}

/**
 * Classe Bike implémentant la BikeInterface
 */
class Bike implements BikeInterface 
{
    public function __construct(
        private string $brand,
        private string $model
    ) {}
      
    public function getBrand() : string 
    {
        return $this->brand;
    }
    public function getModel() : string
    {
        return $this->model;
    }
}

/**
 * La classe Car n'ayant pas la méthode "describe" de l'interface 
 * "VehicleAdapterInterface", nous créons l'adapteur qui l'implémentera.
 */
class CarAdapter implements VehicleAdapterInterface
{
    public function __construct(
        private CarInterface $car
    ) {}
    
    public function describe(): string 
    {
        return sprintf(
            '%s %s %s', 
            $this->car->getBrand(), 
            $this->car->getModel(),
            $this->car->getVersion(),
        );
    }
}

/**
 * La classe Bike n'ayant pas la méthode "describe" de l'interface 
 * "VehicleAdapterInterface", nous créons l'adapteur qui l'implémentera.
 */
class BikeAdapter implements VehicleAdapterInterface
{
    public function __construct(
        private BikeInterface $bike
    ) {}
    
    public function describe(): string 
    {
        return sprintf(
            '%s %s', 
            $this->bike->getBrand(), 
            $this->bike->getModel()
        );
    }
}

// Affichage de la description pour une automobile
$car = new Car("Lancia", "Dedra", "2.0 turbo D");
$carAdapter = new CarAdapter($car);
echo $carAdapter->describe().PHP_EOL;

// Affichage de la description pour une vélo
$bike = new Bike("Decathlon", "Rockrider");
$bikeAdapter = new BikeAdapter($bike);

echo $bikeAdapter->describe();

Utilisations connues

modifier

On peut également utiliser un adaptateur lorsque l'on ne veut pas développer toutes les méthodes d'une certaine interface[réf. nécessaire]. Par exemple, si l'on doit développer l'interface MouseListener en Java, mais que l'on ne souhaite pas développer de comportement pour toutes les méthodes, on peut dériver la classe MouseAdapter. Celle-ci fournit en effet un comportement par défaut (vide) pour toutes les méthodes de MouseListener.

Exemple avec le MouseAdapter :

 public class MouseBeeper extends MouseAdapter
 {
   public void mouseClicked(MouseEvent e) {
     Toolkit.getDefaultToolkit().beep();
   }
 }

Exemple avec le MouseListener :

 public class MouseBeeper implements MouseListener
 {
   public void mouseClicked(MouseEvent e) {
     Toolkit.getDefaultToolkit().beep();
   }

   public void mousePressed(MouseEvent e) {}
   public void mouseReleased(MouseEvent e) {}
   public void mouseEntered(MouseEvent e) {}
   public void mouseExited(MouseEvent e) {}
 }

Notes et références

modifier
  1. « Design Patterns du Gang of Four appliqués à Java », sur Developpez.com (consulté le 21 avril 2023).
  2. Adaptateur sur DoFactory
  3. Conception d'applications en Java/JEE : Principes, patterns et architectures, Dunod, 3 septembre 2014 (lire en ligne)

Voir aussi

modifier

Sur les autres projets Wikimedia :

Articles connexes

modifier

📚 Artikel Terkait di Wikipedia

Loi de Déméter

est qu'elle requiert l'écriture d'un grand nombre de petites méthodes "wrapper" pour propager les appels de méthodes à leurs composants. Cela peut augmenter

Les 100 (série télévisée)

State University, vol. 21,‎ 2017, article no 6 (lire en ligne) : « The pattern of this trope’s usage states that in a narrative work [...], which features

Harvey Weinstein

Monica Hesse, « Violence. Threats. Begging. Harvey Weinstein’s 30-year pattern of abuse in Hollywood. », The Washington Post,‎ 14 octobre 2017 (lire en

Wilfred (série télévisée, 2011)

depuis le 25 juin 2014 sur FXX. Amends Consequences Loyalty Answers Forward Patterns Responsibility Courage Resistance Happiness Ryan Newman Ex-avocat dépressif

Adaptive Communication Environment

couche d’adaptation au système d’exploitation La couche wrapper C++ La couche framework et pattern La couche d’adaptation au système d’exploitation (OSAL :

Data mapper

(data mapper, passerelle de données de table, générateur de requêtes et wrapper PDO) Doctrine : Mapping objet-relationnel (ORM) et la couche d'abstraction

Décorateur (patron de conception)

l'héritage pour composer de nouvelles fonctionnalités. Le pattern Décorateur est l'un des vingt-trois patterns GOF. Il résout les problématiques suivantes : L'ajout

Air Crash

« Season 21 and a 3rd Compilation Season will begin filming on February 27 and wrap up on August 24 according to ACTRA Toronto » [« La saison 21 et une 3e saison