Comprendre le design Pattern Adaptateur

Florian Casabianca

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

- Titre : Comprendre le design Pattern Adaptateur

- Auteur : Florian Casabianca

- Parution : 15 novembre 2007

- Mise à jour : 6 juin 2020

- Licence : 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.

Sommaire

- Introduction

- I. Problématique

- II. Implémentation en C#

- II-A. Les portables à adapter

- II-B. Les adaptateurs

- III. Le pattern Adaptateur : résumé

- IV. Conclusion

- V. Liens

- Remerciements

- Contact

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 faites 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

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

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

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

PortableDeTest

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 fabricant de téléphones 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êmes. 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 leurs téléphones. »

« 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 fabricant 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 peut 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 côté 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 côté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 côté 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

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

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 :

AdaptateurSonneEricSonne

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.

AdaptateurSamSaoule

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, baladeurs 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

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'adaptateur) au chargeur. Nous effectuons la même chose pour un téléphone de marque SamSaoule.

Voici la sortie produite:

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.

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. À 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

Le pattern singleton par Ronald VASSEUR

La rubrique Conception de developpez.com

Les critiques de livres sur les design patterns de developpez.com

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 tutoriel, dans les sources, dans la programmation ou pour toutes informations, n'hésitez pas à me contacter par le forum.