Comprendre le design Pattern Adaptateur

Au travers de cet article nous irons à la découverte du design pattern Adaptateur. Nous verrons la problématique qu'il permet de résoudre ainsi que son implémentation en C#.

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

Introduction

Les magiciens sont des personnes extraordinaires. Ils arrivent à faire des choses qui nous paraissaient impossibles pour nous, simples spectateurs. Mettre en lévitation un éléphant rose ne leur pose aucun souci. Vous êtes jaloux ? Ne vous en faîtes pas, vous allez avoir l'occasion de vous rattraper. Nous aussi nous allons apprendre à créer l'illusion de la réalité: faire passer une interface pour quelque chose qu'elle n'est pas. Cela permettra à des classes de collaborer alors qu'elles n'auraient pas pu le faire du fait d'interfaces incompatibles.

I. Problématique

Pour mieux comprendre l'intérêt du pattern Adaptateur, nous allons commencer par un petit exemple.

La société Carrouf dont vous êtes le directeur souhaite produire un chargeur universel de batteries pour téléphone portable pouvant délivrer jusqu'à 10 volts en sortie. Les ingénieurs de Carrouf ont produit un premier prototype de chargeur:

Chargeur
Sélectionnez
public class Chargeur
{
    // le portable branché sur le chargeur
    private IChargeable telephone;
    // le voltage en sortie du chargeur
    private const int voltage = 10;


    // branchement d'un portable pour le charger
    public void brancherPortable(IChargeable portable)
    {
        Console.WriteLine("branchement d'un portable");
        this.telephone = portable;
        this.telephone.Recharger(voltage);
    }   

}

Celui-ci est capable de se brancher sur tout téléphone implémentant l'interface IChargeable via la méthode brancherPortable et de le recharger en produisant 10 volts en sortie.

Voici le code de l'interface IChargeable:

IChargeable
Sélectionnez
public interface IChargeable
{
    /// <summary>
    /// méthode appelée si l'on veut recharger le portable
    /// </summary>
    /// <param name="volts">voltage en sortie du chargeur</param>
    void Recharger(int volts);
}
image


Vous avez aussi créé plusieurs téléphones portables de test et implémentant l'interface IChargeabledont voici un exemple:

PortableDeTest
Sélectionnez
public class PortableDeTest : IChargeable
{
    public void Recharger(int volts)
    {
        Console.WriteLine("Portable de test en charge");
        Console.WriteLine("voltage: {0}", volts.ToString());        
    }
}

Les tests effectués en laboratoire sont concluants. Le chargeur fonctionne à la perfection avec tous les téléphones implémentant l'interface IChargeable.

Cependant les problèmes apparaissent lors de tests avec les téléphones portables actuellement sur le marché (par exemple avec la marque SonneEricSonne ou encore SamSaoule). En effet, chaque fabriquant de téléphone propose son propre système de chargement. Les interfaces sont non seulement différentes mais le voltage utilisé varie aussi d'un téléphone à l'autre (allant de 10 à 5 volts). Le chargeur universel ne l'est alors plus du tout. Il devient donc impossible d'utiliser notre chargeur avec les téléphones existants. Malheur, la faillite sonne à la porte de la société!

Vous avez donc convoqué les différents responsables pour une réunion de crise afin de trouver une solution au problème.

Nouveau venu dans la boite, Thomas Leblond propose une première solution: "Nous avons besoin que les téléphones implémentent l'interface IChargeable mais nous ne pouvons pas les modifier nous même. Nous n'en possédons pas le code source. Il nous suffit donc de proposer notre interface IChargeable aux différents constructeurs et de leur demander de l'implémenter dans leur téléphone."

"Et puis quoi encore ? "lui rétorqua le chef de projet Didier Valse. "Les constructeurs ont leur propre système et n'ont pas l'intention de le changer. Tu imagines s'ils devaient prendre en compte les demandes des centaines de constructeurs de chargeurs et autres périphériques, ils ne s'en sortiraient pas. Et puis que faire des téléphones déjà vendus ? Ils n'implémenteraient pas IChargeable et ne pourraient donc pas être utilisés par notre chargeur !"

"Ce n'est donc pas au fabriquant du portable à modifier son code mais à nous de nous y adapter. Adapter, voilà un mot intéressant. Ce qu'il nous faudrait c'est en fait quelque chose qui puisse adapter le code des téléphones pour que notre chargeur puisse l'utiliser, un adaptateur en somme."

"D'accord, mais comme faire ? "demanda Thomas.

"Prenons un exemple courant (c'est le cas de le dire): les prises électriques. Si vous voyagez en Angleterre par exemple et tentez de brancher une fiche électrique française sur la prise murale anglaise vous risquez d'avoir quelques problèmes, les interfaces n'étant pas compatibles. Alors que faites vous ? Vous descendez au magasin de bricolage du quartier pour acheter un adaptateur. Un coté de l'adaptateur s'adapte à l'interface de la prise murale anglaise tandis que l'autre s'adapte à la fiche française. Au milieu s'opèrent des transformations afin que les deux cotés puissent communiquer."

"Nous allons donc créer un adaptateur pour chaque portable que l'on voudra utiliser avec notre chargeur. Nous aurons donc un chargeur unique dont le code ne changera pas auquel nous pourrons brancher n'importe quel téléphone en utilisant le bon adaptateur."

Bien joué Didier.

Bon, voyons maintenant comment cela va se traduire au niveau du code.

II. Implémentation en C#

Rappelons qu'un design pattern est une méthode de conception et est donc indépendant (en général) du langage de programmation. Nous allons coder ici en C# mais la méthode est bien sûr tout à fait adaptable à d'autres langages.

Occupons nous d'abord du côté s'interfaçant avec le chargeur. Ce dernier ne manipule que des objets de type IChargeable. L'adaptateur va devoir implémenter l'interface IChargeable afin que le chargeur puisse l'utiliser.

Pour le coté s'adaptant au portable, l'adaptateur devra posséder une référence sur le portable qu'il est censé adapter. C'est en effet l'adaptateur qui manipulera directement l'instance du portable et non pas le chargeur.

II-A. Les portables à adapter

Étudions deux exemples de téléphones portables: SonneEricSonne et SamSaoule. Voici les classes les représentants:

PortableSonneEricSonne
Sélectionnez
public class PortableSonneEricSonne
{
    // ne se recharge qu'avec du 10 volts
    public void ChargerBatteries(int volts)
    {
        Console.WriteLine("Portable SonneEricSonne en charge");
        Console.WriteLine("voltage: {0}", volts.ToString());
    }
}
PortableSamSaoule
Sélectionnez
public class PortableSamSaoule
{
    // ne se recharge qu'avec du 5 volts
    public void ChargerPortable(int volts)
    {
        Console.WriteLine("Portable SamSaoule en charge");
        Console.WriteLine("voltage: {0}", volts.ToString());
    }
}

Les portables possèdent des méthodes différentes pour le rechargement. De plus le voltage à utiliser diffère. Les adaptateurs vont devoir prendre tout cela en considération.

II-B. Les adaptateurs

Nous allons donc construire un adaptateur pour chaque téléphone.

Voici tout d'abord l'adaptateur pour téléphones SonneEricSonne:

image
AdaptateurSonneEricSonne
Sélectionnez
public class AdaptateurSonneEricSonne : IChargeable
{
    // référence sur le portable adapté
    private PortableSonneEricSonne telephone;

    public AdaptateurSonneEricSonne(PortableSonneEricSonne portable)
    {
        this.telephone = portable;
    }


    public void Recharger(int volts)
    {
        this.telephone.ChargerBatteries(volts);
    }
}


L'adaptateur implémente l'interface IChargeable afin de pouvoir être manipulé par le chargeur. Nous utilisons le constructeur de l'adaptateur afin de lui donner une référence sur le téléphone qu'il est censé adapter. Nous gardons cette référence via un champ privé. Il ne reste plus qu'à saisir le code de la méthode Recharger. Le chargeur appelle cette méthode en passant en paramètre le voltage. L'adaptateur se charge d'envoyer cet appel au téléphone dont il s'occupe (lui seul sait comment manipuler un téléphone SonneEricSonne).

Passons maintenant à l'adaptateur pour téléphones SamSaoule.

image
AdaptateurSamSaoule
Sélectionnez
public class AdaptateurSamSaoule : IChargeable
{
    // référence sur le portable adapté
    private PortableSamSaoule telephone;

    public AdaptateurSamSaoule(PortableSamSaoule portable)
    {
        this.telephone = portable;
    }

    //le portable SamSaoule n'a besoin que de 5 volts
    public void Recharger(int volts)
    {
        //on modifie le voltage
        int nouveauVoltage = volts > 5 ? 5 : volts ;

        this.telephone.ChargerPortable(nouveauVoltage);
    }
}


Rien d'extraordinaire par rapport à l'adaptateur précédent. La nouveauté se situe au niveau de la méthode Recharger. Ici l'adaptateur ne se contente pas simplement de traduire les appels du chargeur vers le portable. Vous vous souvenez sans doute que les portables SamSaoule n'ont besoin que de 5 volts. Et bien c'est l'adaptateur qui va se charger d'effectuer la transformation. L'adaptateur encapsule toutes les différences entre le chargeur et le portable.

Le chargeur n'a donc aucun lien avec le portable, seul l'adaptateur connait les spécificités de ce dernier. D'ailleurs, si vous réfléchissez, vous verrez qu'en fait le chargeur ne sait même pas que c'est un téléphone portable qu'il est en train de charger. La société Carrouf l'a bien compris. Elle s'est donc empressée de créer des adaptateurs pour toute sorte d'appareils (piles rechargeables, balladeurs MP3, etc.) tout en gardant le même chargeur de départ.

Maintenant que les adaptateurs sont créés, il ne reste plus qu'à les tester. Voici donc un petit programme en mode console:

Programme de test
Sélectionnez
static void Main(string[] args)
{
    //on crée le chargeur
    Chargeur chargeur = new Chargeur();

    /******************** Portable SonneEricSonne***********************/

    //on crée le portable et son adaptateur
    PortableSonneEricSonne portableSonne = new PortableSonneEricSonne();
    AdaptateurSonneEricSonne adapateurSonne = new AdaptateurSonneEricSonne(portableSonne);

    //on donne le portable à charger mais en utilisant son adaptateur
    chargeur.brancherPortable(adapateurSonne);

    Console.WriteLine();

    /********************* Portable SamSaoule***************************/

    //on crée le portable et son adaptateur
    PortableSamSaoule portableSam = new PortableSamSaoule();
    AdaptateurSamSaoule adapateurSam = new AdaptateurSamSaoule(portableSam);
    
    //on donne le portable à charger mais en utilisant son adaptateur
    chargeur.brancherPortable(adapateurSam);

    Console.ReadLine();
}

Nous créons tout d'abord un nouvel objet chargeur. Puis nous instancions un portable de type PortableSonneEricSonne que nous passons en paramètre d'un adaptateur de type AdaptateurSonneEricSonne. Enfin nous branchons le portable (par l'intermédiaire de l'adapateur) au chargeur. Nous effectuons la même chose pour un téléphone de marque SamSaoule.

Voici la sortie produite:

image


Comme vous le voyez, les adaptateurs ont parfaitement fonctionné. Nous avons pu recharger des téléphones de marques différentes grâce aux adaptateurs. De plus, l'adaptateur pour téléphone SamSaoule a bien adapté le voltage en le ramenant à 5.

III. Le pattern Adaptateur: résumé

Le pattern Adaptateur permet de transformer une interface d'une classe en une autre conforme à celle attendue par le client. L'adaptateur permet à des classes de collaborer alors qu'elles n'auraient pas pu le faire du fait d'interfaces incompatibles.

image

Bien que l'on utilise généralement le pattern Adaptateur pour convertir une interface en une autre, il peut arriver qu'un adaptateur ait besoin de plusieurs adaptés afin d'implémenter complètement l'interface cible.

IV. Conclusion

Ici s'achève notre découverte du pattern Adaptateur. A partir de maintenant lorsque vous devrez utiliser une classe existante et que son interface ne correspond pas à celle que vous attendez, vous saurez quoi faire.

V. Liens

Remerciements

J'adresse ici tous mes remerciements à l'équipe de rédaction de "developpez.com" pour le temps qu'ils ont bien voulu passer à la correction et à l'amélioration de cet article.

Contact

Si vous constatez une erreur dans le tutorial, dans les sources, dans la programmation ou pour toutes informations, n'hésitez pas à me contacter par le forum.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2007 Florian Casabianca. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.