Patrons de conception/Adaptateur

Un livre de Wikilivres.
Patron de conception
Catégorie : « Gang of Four »Structure
Nom français : Adaptateur
Nom anglais : Adapter, Wrapper
Convertir une interface existante afin de la rendre compatible avec une autre interface


Adaptateur est un patron de conception qui permet de convertir l'interface d'une classe en une autre interface que le client attend. Adaptateur fait fonctionner un ensemble de classes qui n'auraient pas pu fonctionner sans lui, à cause d'une incompatibilité d'interfaces.

Exemple[modifier | modifier le wikicode]

Vous voulez intégrer une classe que vous ne voulez/pouvez pas modifier, ou développer un middleware entre différentes applications.

Applicabilité[modifier | modifier le wikicode]

  • Une API tiers convient à votre besoin fonctionnel, mais la signature de ses méthodes ne vous convient pas.
  • Vous voulez normaliser l'utilisation d'anciennes classes sans pour autant en reprendre tout le code.

Diagramme de classes UML[modifier | modifier le wikicode]

Le patron de conception Adaptateur peut être représenté par le diagramme de classes UML suivant :

Diagramme de classes UML du patron de conception Adaptateur
  • IAdaptateur : Définit l'interface métier utilisée par la classe cliente.
  • Adapté : Définit une interface existante devant être adaptée.
  • Adaptateur : Fait correspondre l'interface de Adapté à l'interface IAdaptateur, en convertissant l'appel aux méthodes de l'interface IAdaptateur en des appels aux méthodes de la classe Adapté.

Conséquences[modifier | modifier le wikicode]

Un objet Adaptateur sert de liaison entre les objets manipulés et un programme les utilisant, à simplifier la communication entre deux classes. Il est utilisé pour modifier l'interface d'un objet vers une autre interface.

Exemples[modifier | modifier le wikicode]

C++[modifier | modifier le wikicode]

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 CarreCoinsRondAdapter: public Carre, private Cercle
{
  public:
    CarreCoinsRondAdapter();

    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();
    }
};

C#[modifier | modifier le wikicode]

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

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

/// <summary> "Adapté" qui n'a pas la signature "IAdaptateur" </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 _architecte;
    public Adaptateur (Architecte archi)
    {
        _architecte = archi;
    }
    public string EcrireCode()
    {
        return string.Format(
            "let main() = printfn \"{0} codé\"",
            _architecte.EcrireAlgorithme());
    }
}

//___________________________________________________________________
// Implémentation

/// <summary> "Client" qui n'utilise que les objets qui respectent la signature </summary>
class Client
{
    void Utiliser(IDeveloppeur developpeur)
    {
        Console.WriteLine(developpeur.EcrireCode());
    }

    static void Main()
    {
        var client = new Client();

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

        var architecte = new Architecte();
        IDeveloppeur developpeur2 = new Adaptateur(architecte);
        client.Utiliser(developpeur2);
    }
}

Utilisations connues[modifier | modifier le wikicode]

On peut également utiliser un adaptateur lorsque l'on ne veut pas implémenter toutes les méthodes d'une certaine interface. Par exemple, si l'on doit implémenter l'interface MouseListener en Java, mais que l'on ne souhaite pas implémenter 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 MouseAdapter :

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

Exemple avec 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) {}
}

Voir aussi[modifier | modifier le wikicode]

Patron de conception connexes[modifier | modifier le wikicode]

Liens et documents externes[modifier | modifier le wikicode]