Patron Adaptateur
Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy — leçon 71 sur 87.
Le Pattern Adaptateur est un patron de conception structurel qui permet à des interfaces incompatibles de travailler ensemble. Il agit comme un pont entre deux classes, convertissant l'interface d'une classe en une interface attendue par le client. Pensez-y comme à un adaptateur secteur qui vous permet de brancher un appareil européen sur une prise américaine.
Imaginez que vous ayez une interface MediaPlayer existante qui lit des fichiers audio, mais que vous deviez intégrer une bibliothèque tierce qui utilise une interface complètement différente pour lire des vidéos :
// Interface existante utilisée par votre code
interface MediaPlayer {
void play(String filename);
}
// Classe tierce avec une interface incompatible
class AdvancedVideoPlayer {
public void playVideo(String filename) {
System.out.println("Playing video: " + filename);
}
}L'adaptateur enveloppe la classe incompatible et implémente l'interface attendue, en traduisant les appels entre elles :
class VideoPlayerAdapter implements MediaPlayer {
private AdvancedVideoPlayer videoPlayer;
public VideoPlayerAdapter() {
this.videoPlayer = new AdvancedVideoPlayer();
}
public void play(String filename) {
videoPlayer.playVideo(filename);
}
}Désormais, votre code client peut utiliser le lecteur vidéo via l'interface familière MediaPlayer :
MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4"); // Sortie : Lecture de la vidéo : movie.mp4Le pattern Adapter est inestimable lors de l'intégration de code hérité ou de bibliothèques tierces sans modifier leur code source. Le client ne sait pas qu'il travaille avec une classe adaptée — il utilise simplement l'interface qu'il connaît.
Défi
FacileConstruisons un système de conversion de température en utilisant le Design Pattern Adapter ! Vous avez une application météo existante qui fonctionne avec des températures en Celsius, mais vous devez intégrer un ancien capteur de température qui ne fournit que des relevés en Fahrenheit. Au lieu de modifier l'un ou l'autre système, vous allez créer un adaptateur qui comble l'écart.
Vous organiserez votre code sur quatre fichiers :
TemperatureProvider.java: Définissez l'interface attendue par votre application météo. Elle doit déclarer une méthodegetTemperatureCelsius()qui retourne un double représentant la température en Celsius.FahrenheitSensor.java: Ceci représente le capteur hérité avec une interface incompatible. Créez une classe avec un champ privé de type double pour la température en Fahrenheit, défini via le constructeur. Elle doit avoir une méthodereadFahrenheit()qui retourne la valeur Fahrenheit stockée.SensorAdapter.java: Créez l'adaptateur qui rend le capteur Fahrenheit compatible avec votre application météo. Votre adaptateur doit implémenterTemperatureProvideret envelopper unFahrenheitSensor. LorsquegetTemperatureCelsius()est appelée, elle doit lire la valeur du capteur et la convertir en Celsius en utilisant la formule :(fahrenheit - 32) * 5 / 9.Main.java: Rassemblez le tout ! Vous recevrez une entrée : un relevé de température en Fahrenheit (double).Créez un
FahrenheitSensoravec la valeur d'entrée. Ensuite, créez unSensorAdapterqui enveloppe ce capteur. Stockez l'adaptateur dans une variable de typeTemperatureProviderpour démontrer que votre application météo peut l'utiliser via l'interface attendue.Affichez le résultat dans ce format :
Temperature: [celsius] Coù celsius est formaté avec une décimale.
Vous recevrez une entrée : la température en Fahrenheit (double).
Par exemple, avec l'entrée 98.6, votre sortie serait :
Temperature: 37.0 CRemarquez comment votre classe Main travaille entièrement avec l'interface TemperatureProvider — elle n'a aucune idée que la température réelle provient d'un capteur Fahrenheit adapté en coulisses. C'est toute l'élégance du Pattern Adapter !
Aide-mémoire
Le Pattern Adaptateur (Adapter Pattern) est un patron de conception structurel qui permet à des interfaces incompatibles de travailler ensemble en agissant comme un pont entre deux classes, convertissant une interface en une autre attendue par le client.
Composants clés
- Interface Cible (Target Interface) : L'interface que le client s'attend à utiliser
- Adapté (Adaptee) : La classe existante avec une interface incompatible
- Adaptateur (Adapter) : La classe qui implémente l'interface cible et enveloppe l'adapté, traduisant les appels entre eux
Structure de base
// Interface cible
interface MediaPlayer {
void play(String filename);
}
// Adapté (classe incompatible)
class AdvancedVideoPlayer {
public void playVideo(String filename) {
System.out.println("Playing video: " + filename);
}
}
// Adaptateur
class VideoPlayerAdapter implements MediaPlayer {
private AdvancedVideoPlayer videoPlayer;
public VideoPlayerAdapter() {
this.videoPlayer = new AdvancedVideoPlayer();
}
public void play(String filename) {
videoPlayer.playVideo(filename);
}
}
// Utilisation par le client
MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4"); // Sortie : Playing video: movie.mp4Quand l'utiliser
Le Pattern Adaptateur est utile lorsque :
- Vous intégrez du code hérité ou des bibliothèques tierces sans modifier leur code source
- Vous devez faire fonctionner ensemble des interfaces incompatibles
- Le client doit rester ignorant de l'implémentation adaptée
Essayez vous-même
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double fahrenheit = scanner.nextDouble();
// TODO: Créer un FahrenheitSensor avec la valeur d'entrée
// TODO: Créer un SensorAdapter qui enveloppe le capteur
// TODO: Stocker l'adaptateur dans une variable TemperatureProvider
// TODO: Obtenir la température en Celsius et l'afficher
// Format: "Temperature: [celsius] C" avec une décimale
// Astuce: Utiliser String.format("%.1f", value) pour le formatage
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe mot-clé thisMéthodesChamps (Attributs)Méthode constructeurSurcharge de constructeurRécapitulatif - Calculatrice simple4Héritage
Héritage de base (extends)Le mot-clé superRedéfinition de méthode (@Override)Chaînage de constructeursLa classe ObjectHéritage simple et multiniveauPourquoi pas d'héritage multiple de classesRécapitulatif - Hiérarchie des employés7Méthodes spéciales et classe Object
Méthode toString()equals() et hashCode()Méthode clone()compareTo() et ComparableInterface ComparatorRécapitulatif - Tri personnalisé2Modificateurs d'accès et Encapsulation
Aperçu des niveaux d'accèsMéthodes Getter et SetterMasquage d'informationsLe mot-clé finalRécapitulatif - Gestionnaire de compte bancaire5Polymorphisme
Bases de la surcharge de méthodesRedéfinition de méthodes (Run-Time)Upcasting et DowncastingL'opérateur instanceofClasses et méthodes abstraitesRécapitulatif - Calculateur de formes8Concepts avancés de la POO
Composition vs HéritageAgrégation vs CompositionClasses internes, imbriquées et anonymesEnums et méthodes d'EnumRecords (Java 16+)Classes scellées (Java 17+)11Patrons de conception, partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron MonteurPatron ObservateurPatron Stratégie3Propriétés de classe et membres statiques
Variables d'instance vs variables statiquesMéthodes statiquesBlocs statiquesConstantes (static final)Récapitulatif - Compteur et utilitaire6Interfaces et Classes Abstraites
Introduction aux InterfacesImplémentation d'InterfacesImplémentation d'Interfaces MultiplesDefault et Static dans les InterfacesClasses Abstraites vs InterfacesInterfaces FonctionnellesRécapitulatif - Système de Paiement9La généricité
Introduction à la généricitéClasses génériquesMéthodes génériquesParamètres de type bornésWildcards (?, extends, super)Récapitulatif - Conteneur générique12Patrons de conception, partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositePatron Itérateur