Menu
Coddy logo textTech

Patron Adaptateur

Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 95 sur 110.

Le pattern Adapter permet à des interfaces incompatibles de travailler ensemble. Il agit comme un pont entre deux classes qui ne pourraient pas collaborer autrement, en enveloppant une classe existante avec une nouvelle interface attendue par les clients. Ceci est particulièrement utile lors de l'intégration de bibliothèques tierces ou de code hérité dans votre application.

Imaginez que vous ayez un système qui travaille avec des données JSON, mais que vous deviez intégrer un composant qui ne produit que du XML. Au lieu de modifier l'une ou l'autre classe, vous créez un adaptateur qui effectue la traduction entre les deux :

// Interface existante attendue par votre système
abstract class JsonData {
  String getJson();
}

// Classe héritée avec une interface incompatible
class XmlService {
  String getXml() {
    return '<data><name>John</name></data>';
  }
}

// L'adaptateur rend XmlService compatible avec JsonData
class XmlToJsonAdapter implements JsonData {
  final XmlService _xmlService;

  XmlToJsonAdapter(this._xmlService);

  @override
  String getJson() {
    String xml = _xmlService.getXml();
    // Convertir le XML en JSON (simplifié)
    return '{"name": "John"}';
  }
}

void main() {
  var xmlService = XmlService();
  var adapter = XmlToJsonAdapter(xmlService);

  print(adapter.getJson());  // {"name": "John"}
}

L'XmlToJsonAdapter enveloppe le XmlService et implémente l'interface JsonData. Le code client travaille avec l'interface familière JsonData sans savoir que les données provenaient initialement d'une source XML. L'adaptateur gère toute la traduction en interne.

Utilisez le patron Adaptateur lorsque vous souhaitez utiliser une classe existante mais que son interface ne correspond pas à ce dont vous avez besoin, ou lorsque vous devez créer une classe réutilisable qui coopère avec des classes ayant des interfaces incompatibles.

challenge icon

Défi

Facile

Construisons un système d'adaptateur de lecteur multimédia ! Imaginez que vous avez un système audio moderne qui s'attend à ce que toutes les sources multimédias fournissent de l'audio via une interface standard, mais vous devez intégrer un vieux tourne-disque vinyle qui a une manière complètement différente de produire du son.

Vous allez créer deux fichiers pour organiser votre implémentation du pattern adapter :

  • media_adapter.dart : Ce fichier contient votre interface et vos classes d'adaptateur. Définissez une classe abstraite AudioSource que votre système moderne attend - elle doit avoir une méthode String playAudio() qui retourne la sortie audio sous forme de chaîne de caractères. Créez ensuite une classe VinylPlayer représentant l'équipement hérité - elle possède un champ trackName et une méthode String spinRecord() qui retourne *crackle* Playing vinyl: [trackName] *crackle*. Enfin, construisez un VinylAdapter qui implémente AudioSource et enveloppe un VinylPlayer. La méthode playAudio() de l'adaptateur doit appeler la méthode spinRecord() du lecteur vinyle et retourner le résultat - comblant ainsi le fossé entre les interfaces incompatibles.
  • main.dart : Importez votre fichier d'adaptateur multimédia et démontrez comment l'adaptateur permet au vieux lecteur vinyle de fonctionner avec du code qui attend l'interface moderne AudioSource. Créez un VinylPlayer avec le nom de piste Bohemian Rhapsody. Créez ensuite un VinylAdapter qui enveloppe ce lecteur vinyle. Stockez l'adaptateur dans une variable de type AudioSource pour prouver qu'il se conforme à l'interface attendue. Appelez playAudio() sur votre source audio et affichez le résultat.

La beauté de ce pattern est que votre code principal travaille avec l'interface standard AudioSource - il n'a pas besoin de savoir qu'en coulisses, un vieux lecteur vinyle fait le travail réel !

Sortie attendue :

*crackle* Playing vinyl: Bohemian Rhapsody *crackle*

Aide-mémoire

Le pattern Adapter (ou Adaptateur) permet à des interfaces incompatibles de travailler ensemble en agissant comme un pont entre deux classes qui ne pourraient pas collaborer autrement.

L'adaptateur enveloppe une classe existante avec une nouvelle interface attendue par les clients, ce qui le rend utile lors de l'intégration de bibliothèques tierces ou de code hérité.

Structure de base

// Interface cible attendue par les clients
abstract class JsonData {
  String getJson();
}

// Classe existante avec une interface incompatible
class XmlService {
  String getXml() {
    return '<data><name>John</name></data>';
  }
}

// L'adaptateur rend XmlService compatible avec JsonData
class XmlToJsonAdapter implements JsonData {
  final XmlService _xmlService;

  XmlToJsonAdapter(this._xmlService);

  @override
  String getJson() {
    String xml = _xmlService.getXml();
    // Convertir le XML en JSON
    return '{"name": "John"}';
  }
}

Utilisation

void main() {
  var xmlService = XmlService();
  var adapter = XmlToJsonAdapter(xmlService);

  print(adapter.getJson());  // {"name": "John"}
}

L'adaptateur implémente l'interface cible tout en enveloppant la classe incompatible. Le code client utilise l'interface familière sans connaître l'implémentation sous-jacente.

Quand l'utiliser : Lorsque vous devez utiliser une classe existante mais que son interface ne correspond pas à vos besoins, ou lors de la création d'une classe réutilisable qui coopère avec des classes ayant des interfaces incompatibles.

Essayez vous-même

import 'media_adapter.dart';

void main() {
  // TODO: Créer un VinylPlayer avec le nom de piste "Bohemian Rhapsody"
  
  // TODO: Créer un VinylAdapter qui enveloppe le lecteur vinyle
  
  // TODO: Stocker l'adaptateur dans une variable de type AudioSource
  
  // TODO: Appeler playAudio() sur votre source audio et imprimer le résultat
  
}
quiz iconTestez-vous

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