Patron Adaptateur
Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy — leçon 57 sur 70.
Le pattern Adapter est un patron de structure 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 les clients. Pensez-y comme à un adaptateur secteur qui vous permet de brancher un appareil européen sur une prise américaine.
Ce patron est particulièrement utile lorsque vous souhaitez utiliser une classe existante mais que son interface ne correspond pas à ce dont votre code a besoin. Au lieu de modifier la classe d'origine (que vous ne contrôlez peut-être pas), vous créez un adaptateur qui l'enveloppe :
// Classe existante avec une interface incompatible
public class OldPrinter
{
public void PrintMessage(string msg) => Console.WriteLine($"Old: {msg}");
}
// Interface attendue par votre code
public interface IPrinter
{
void Print(string text);
}
// L'adaptateur comble l'écart
public class PrinterAdapter : IPrinter
{
private OldPrinter _oldPrinter;
public PrinterAdapter(OldPrinter oldPrinter)
{
_oldPrinter = oldPrinter;
}
public void Print(string text)
{
_oldPrinter.PrintMessage(text); // Délègue à l'ancienne interface
}
}Désormais, votre code peut fonctionner avec l'ancienne imprimante via l'interface attendue :
OldPrinter legacy = new OldPrinter();
IPrinter printer = new PrinterAdapter(legacy);
printer.Print("Hello"); // Ancien : HelloLe pattern Adapter est inestimable lors de l'intégration de bibliothèques tierces ou de code hérité dans votre application. Le code client travaille avec l'interface IPrinter, ignorant complètement qu'une ancienne classe incompatible effectue le travail réel en coulisses.
Défi
FacileConstruisons un système de lecteur multimédia en utilisant le motif Adaptateur (Adapter pattern). Vous disposez d'une bibliothèque audio existante qui lit des fichiers MP3, mais votre application a besoin d'une interface unifiée capable de gérer différents types de médias. Vous allez créer un adaptateur pour combler cet écart, permettant à votre lecteur multimédia moderne de fonctionner de manière transparente avec la bibliothèque audio héritée.
Vous organiserez votre code sur trois fichiers :
LegacyAudio.cs: Cela représente une bibliothèque existante que vous ne pouvez pas modifier. Créez une classeLegacyAudioPlayerdans l'espace de nomsMediaSystemavec une méthodePlayMp3(string filename)qui retourne la chaîne"Playing MP3: {filename}". C'est votre "adaptee" - la classe avec l'interface incompatible.MediaAdapter.cs: Créez l'interface et l'adaptateur dans le même espace de noms. Définissez une interfaceIMediaPlayeravec une méthodePlay(string filename)qui retourne une chaîne de caractères. Ensuite, créez une classeMediaPlayerAdapterqui implémenteIMediaPlayer. Votre adaptateur doit envelopper une instance deLegacyAudioPlayer(passée via le constructeur) et traduire l'appelPlayvers la méthodePlayMp3du lecteur hérité.Program.cs: Rassemblez le tout en créant le lecteur hérité, en l'enveloppant dans votre adaptateur et en utilisant l'adaptateur via l'interfaceIMediaPlayer. Cela démontre comment le code client peut travailler avec l'interface moderne tandis que l'adaptateur gère la communication avec le système hérité en coulisses.
Vous recevrez une entrée :
- Le nom du fichier à lire (par exemple,
song.mp3)
Créez un LegacyAudioPlayer, enveloppez-le dans un MediaPlayerAdapter, puis appelez Play sur l'adaptateur en utilisant l'interface IMediaPlayer et affichez le résultat.
Par exemple, si l'entrée est favorite_track.mp3, la sortie doit être :
Playing MP3: favorite_track.mp3La beauté de ce motif est que votre code principal interagit uniquement avec IMediaPlayer - il n'a aucune idée qu'une bibliothèque audio héritée effectue le travail réel. Si vous devez plus tard prendre en charge une autre bibliothèque héritée, il vous suffira de créer un nouvel adaptateur sans modifier le code client !
Aide-mémoire
Le pattern Adaptateur (Adapter pattern) est un pattern structurel qui permet à des interfaces incompatibles de fonctionner ensemble en agissant comme un pont entre deux classes.
Ce pattern convertit l'interface d'une classe en une interface attendue par les clients, ce qui est utile lorsque vous souhaitez utiliser une classe existante mais que son interface ne correspond pas aux besoins de votre code.
Structure de base :
// Existing class with incompatible interface (Adaptee)
public class OldPrinter
{
public void PrintMessage(string msg) => Console.WriteLine($"Old: {msg}");
}
// Target interface your code expects
public interface IPrinter
{
void Print(string text);
}
// Adapter bridges the gap
public class PrinterAdapter : IPrinter
{
private OldPrinter _oldPrinter;
public PrinterAdapter(OldPrinter oldPrinter)
{
_oldPrinter = oldPrinter;
}
public void Print(string text)
{
_oldPrinter.PrintMessage(text); // Delegates to old interface
}
}Utilisation :
OldPrinter legacy = new OldPrinter();
IPrinter printer = new PrinterAdapter(legacy);
printer.Print("Hello"); // Old: HelloLe code client travaille avec l'interface cible, sans savoir qu'une classe incompatible effectue le travail réel en coulisses. Ce pattern est particulièrement précieux lors de l'intégration de bibliothèques tierces ou de code hérité (legacy).
Essayez vous-même
using System;
using MediaSystem;
class Program
{
public static void Main(string[] args)
{
// Lire l'entrée du nom de fichier
string filename = Console.ReadLine();
// TODO: Créer une instance de LegacyAudioPlayer
// TODO: L'envelopper dans un MediaPlayerAdapter
// TODO: Utiliser l'adaptateur via l'interface IMediaPlayer
// et afficher le résultat de l'appel à Play avec le nom de fichier
}
}
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 externesEspaces de noms et directivesIntro aux classes et objetsLe mot-clé 'this'Méthodes et paramètresChamps vs PropriétésConstructeursInitialiseurs d'objetsRécapitulatif - Calculatrice simple4Héritage
Syntaxe de base de l'héritage (:)Le mot-clé 'base'Mots-clés Virtual & OverrideClasses scelléesLa classe de base 'object'Récapitulatif - Hiérarchie des employés7Fonctionnalités avancées
Surcharge d'opérateursIndexeurs (this[])Redéfinition de ToString()Méthodes d'extensionRécapitulatif - Liste personnalisée10Patrons de conception - Partie 1
Introduction aux patrons de conceptionSingleton Thread-SafePatron FabriquePatron Observateur (Événements)Patron Stratégie2Propriétés et membres statiques
Propriétés auto-implémentéesPropriétés en lecture/écriture seuleChamps et méthodes statiquesClasses statiquesMembres à corps d'expression5Polymorphisme & Interfaces
Polymorphisme : Compilation vs ExécutionInterface vs Classe AbstraiteInterfaces MultiplesInterfaces ExplicitesUpcasting & DowncastingRécapitulatif - Calculateur de Formes8Concepts avancés de la POO
Composition plutôt qu'héritageGénériques (Classes et Méthodes)Délégués et ÉvénementsAttributs et RéflexionIDisposable et l'instruction usingBases de l'Injection de Dépendances11Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode TemplatePatron ÉtatPatron Composite3Architecture des classes
Données d'instance vs statiquesMots-clés 'readonly' & 'const'Champs de supportRécapitulatif - Gestionnaire de compte bancaire6Encapsulation
Modificateurs d'accèsPropriétés pour l'encapsulationImplémentation du masquage de donnéesPatterns d'immuabilitéRécapitulatif - Dossiers d'étudiants12Projet : Système de gestion de bibliothèque
Structure du projetModèles Livre et Utilisateur