Adapter
(Adaptateur)

Autre nom : Wrapper
Convertit l'interface d'une classe en une interface attendue par les clients.
Dans le cas le plus simple, sert à faire collaborer 2 systèmes qui font (plus ou moins) les mêmes choses avec 2 vocabulaires différents.

Exemple

(code dans Chevaux1.java).

On a un programme qui manipule différents types de chevaux : ChevalDeCamargue, ChevalArabe, PoneyShetland.
Tous ces chevaux implémentent l'interface Cheval :
interface Cheval{
    public void hennir();
}
On peut par exemple les utiliser de cette manière :
public static void main(String[] args){
    Cheval[] chevaux = {
        new ChevalDeCamargue(),
        new ChevalArabe(),
        new PoneyShetland(),
    };
    for(Cheval cheval : chevaux){
        cheval.hennir();
    }
}
On nous fournit une classe Ane
class Ane{
    public void braire(){
        System.out.println("hi han");
    }
}
Comment faire pour utiliser un âne de la même manière qu'on utilise un cheval ?
Pouvoir écrire du code du genre :
Cheval[] chevaux = {
    new ChevalDeCamargue(),
    new ChevalArabe(),
    new PoneyShetland(),
    new Ane(),
};
Le pattern Adapter permet de répondre à cette question.

Utilisation de l'héritage

(code dans Chevaux2.java).

La classe AneAdapter dérive de Ane et implémente en plus Cheval
class AneAdapter extends Ane implements Cheval{
    public void hennir(){
        braire();
    }
}
La classe AneAdapter absorbe la différence entre Ane et Cheval grâce à l'héritage.

A l'utilisation :
Cheval[] chevaux = {
    new ChevalDeCamargue(),
    new ChevalArabe(),
    new PoneyShetland(),
    new AneAdapter(),
};
Note : Ce type d'adapter est parfois appellé class adapter.

Structure

Adapter cheval héritage La présentation classique (gof) utilise l'héritage : Adapter
Exercice : Identifiez Cheval, Ane et AneAdapter dans le schéma gof.

Utilisation de la composition

(code dans Chevaux3.java).

On crée une classe AneAdapter qui implémente l'interface Cheval et qui contient un Ane.
(noter que le constructeur de AneAdapter prend un Ane en paramètre).
class AneAdapter implements Cheval{

    private Ane ane;
    
    public AneAdapter(Ane ane){
        this.ane = ane;
    }
    
    public void hennir(){
        ane.braire();
    }
}
La classe AneAdapter absorbe la différence entre Ane et Cheval grâce à la composition.

Cela permet d'utiliser un AneAdapter chaque fois qu'on veut faire passer un âne pour un cheval :
Cheval[] chevaux = {
    new ChevalDeCamargue(),
    new ChevalArabe(),
    new PoneyShetland(),
    new AneAdapter(new Ane()),
};
Adapter cheval composition Note : Ce type d'adapter est parfois appellé object adapter.

Remarques

Certains adapteurs peuvent être plus complexes, cela va de la simple traduction de vocabulaire à l'implémentation de fonctionnalités.
Dépend du degré de similitude entre Target et Adaptee.

Le classe Adaptee contient l'implémentation, c'est elle qui fait le travail.

ATTENTION : la classe Adapter ne répète pas l'implémentation de Adaptee mais la réutilise.
Exercice : Adapter Menu
Exercice : Adapter Pile / Stack