Pattern Adapter

1. Problème initial

Comment faire pour utiliser un code qui n’est pas « compatible » avec votre code ?

2. Solution associée

On utilise une interface qui va faire le lien entre deux codes différents pour les rendre compatible.

3. Définition et exemple

De même que pour le pattern Composite nous allons partir d’un exemple pour mieux comprendre ce pattern.

Soit une classe AudioPlayer qui implémente une interface MediaPlayer. AudioPlayer permet de lire des fichiers audio au format mp3 par défaut.



A côté de ça nous allons avoir deux autres classes, VLCPlayer et MP4Player qui implémentent l’interface AdvancedMediaPlayer. Ces classes peuvent jouer des fichiers vlc et format mp4.



Nous voulons faire en sorte qu’AudioPlayer puisse jouer d'autres formats que simplement le format MP3.

Pour y parvenir nous allons créer une classe adaptateur MediaAdapter qui va se charger, à terme, de permettre à AudioPlayer de jouer un fichier au format mp4 ou vlc.

On va tout d’abord la faire implémenter l’interface MediaPlayer pour qu’elle puisse implémenter la même méthode que la classe AudioPlayer, la méthode play().



Ensuite on créer une relation entre la classe AudioPlayer et la classe MediaAdapter de telle sorte que le classe AudioPlayer ait accès aux méthodes de la classe MediaAdapter.



Ensuite il faut que MediaAdapter ait accès aux méthodes de AdvancedMediaPlayer pour pouvoir les appeler en temps voulu quand la classe AudioPlayer le demandera.
Or on ne peut pas « implements » cette interface car cela obligerait MediaAdapter à les redéfinir. A la place on va donc créer une variable advancedMusicPlayer de type AdvancedMediaPlayer !
On a donc :



Maintenant le principe va être le suivant : quand on demandera à AudioPlayer de jouer un fichier d’un certain format avec la méthode play() on aura deux cas de figures :
- Soit le format est du mp3 alors on réalise les actions que l’on avait prévu au départ c’est-à-dire quand on n’avait pas décidé que AudioPlayer devait gérer d’autres formats. - Soit le format est un format étranger à AudioPlayer (mp4 ou vlc) et alors il nous faut passer par la classe MediaAdapter pour avoir accès aux bonnes méthodes issues de l’interface AdvancedMediaPlayer.

Comment implémenter le second cas de figure ?
C’est simple dès le moment où on demande à AudioPlayer de lire un format étranger, celle-ci va créer une instance de MediaAdapter en lui passant le type étranger que l’on souhaite lire.
Ainsi la nouvelle instance de MediaAdapter initialise la variable advancedMusicPlayer en créant une instance de la bonne classe correspondant au format (soit une instance de VLCPlayer si le format passé était vlc sinon une instance de MP4Player).


Ensuite la classe AudioPlayer peut faire appel à la méthode play() de la nouvelle instance de MediaAdapter fraichement crée, méthode dont les actions dépendent du type de l’instance de MediaAdapter. Les actions de play() pour un objet VLCPlayer ne sont pas les mêmes que pour un objet MP4Player !

Le code correspondant est le suivant :

Pour la classe AudioAdapter :



Pour la classe MediaAdapter :



4. A retenir

Pour appliquer ce pattern une fois encore pas simpliste il faut :
  • Avoir deux interfaces ou classes abstraites qui possèdent une méthode qui fait la même chose mais pas pour les mêmes objets et pas de la même façon (la méthode play()).
  • Avoir des classes qui implémentent/héritent de ces deux interfaces/classes abstraites.
  • Trouver la classe Client c’est-à-dire celle qui va être solicitée pour réaliser une action qu’elle ne peut pas faire selon le type (AudioPlayer ne pouvait pas lire des fichiers au format vlc ou mp4 au début).
  • Faire une nouvelle classe, la classe Adapter qui va implémenter la même interface que celle de la classe Client.
  • Dans la classe Client, créer une variable du type de l’adapter qu’on instanciera lorsque le Client reçoit un format étranger.
  • Dans la classe Adapter, créer une variable du type de l’autre interface (celle qu’elle n’implémente pas) pour pouvoir créer un sous-objet de cette classe en fonction de ce que la classe Client demandera.