Pattern Adapter
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 95 di 110.
Il pattern Adapter consente a interfacce incompatibili di lavorare insieme. Agisce da ponte tra due classi che altrimenti non potrebbero collaborare, avvolgendo una classe esistente con una nuova interfaccia che i client si aspettano. È particolarmente utile quando si integrano librerie di terze parti o codice legacy nella propria applicazione.
Immagina di avere un sistema che lavora con dati JSON, ma devi integrare un componente che produce solo XML. Invece di modificare una delle due classi, crei un adattatore che traduce tra loro:
// Interfaccia esistente prevista dal sistema
abstract class JsonData {
String getJson();
}
// Classe legacy con un'interfaccia incompatibile
class XmlService {
String getXml() {
return '<data><name>John</name></data>';
}
}
// L'adattatore rende XmlService compatibile con JsonData
class XmlToJsonAdapter implements JsonData {
final XmlService _xmlService;
XmlToJsonAdapter(this._xmlService);
@override
String getJson() {
String xml = _xmlService.getXml();
// Converti XML in JSON (versione semplificata)
return '{"name": "John"}';
}
}
void main() {
var xmlService = XmlService();
var adapter = XmlToJsonAdapter(xmlService);
print(adapter.getJson()); // {"name": "John"}
}XmlToJsonAdapter avvolge XmlService e implementa l’interfaccia JsonData. Il codice client lavora con la familiare interfaccia JsonData senza sapere che i dati provengono originariamente da una sorgente XML. L’adattatore gestisce internamente tutta la traduzione.
Usa il pattern Adapter quando vuoi usare una classe esistente ma la sua interfaccia non corrisponde a ciò di cui hai bisogno, oppure quando devi creare una classe riutilizzabile che collabori con classi dotate di interfacce incompatibili.
Sfida
FacileCostruiamo un sistema adattatore per lettori multimediali! Immagina di avere un moderno sistema audio che si aspetta che tutte le sorgenti multimediali forniscano audio tramite un'interfaccia standard, ma devi integrare un vecchio giradischi in vinile che produce il suono in modo completamente diverso.
Creerai due file per organizzare l'implementazione del pattern adapter:
media_adapter.dart: questo file contiene l'interfaccia e le classi adattatore. Definisci una classe astrattaAudioSourceche il tuo sistema moderno si aspetta: deve avere un metodoString playAudio()che restituisce l'uscita audio come stringa. Poi crea una classeVinylPlayerche rappresenta l'apparecchiatura legacy: ha un campotrackNamee un metodoString spinRecord()che restituisce*crackle* Playing vinyl: [trackName] *crackle*. Infine, crea unVinylAdapterche implementaAudioSourcee avvolge unVinylPlayer. Il metodoplayAudio()dell'adattatore dovrebbe chiamare il metodospinRecord()del lettore in vinile e restituire il risultato, collegando così le interfacce incompatibili.main.dart: importa il file dell'adattatore multimediale e mostra come l'adattatore consente al vecchio lettore in vinile di funzionare con codice che si aspetta l'interfaccia modernaAudioSource. Crea unVinylPlayercon il nome della tracciaBohemian Rhapsody. Poi crea unVinylAdapterche avvolge questo lettore in vinile. Memorizza l'adattatore in una variabile di tipoAudioSourceper dimostrare che è conforme all'interfaccia prevista. ChiamaplayAudio()sulla tua sorgente audio e stampa il risultato.
La bellezza di questo pattern è che il codice principale funziona con l'interfaccia standard AudioSource: non ha bisogno di sapere che, dietro le quinte, è un vecchio lettore in vinile a svolgere il lavoro effettivo!
Output previsto:
*crackle* Playing vinyl: Bohemian Rhapsody *crackle*Provalo tu
import 'media_adapter.dart';
void main() {
// TODO: Crea un VinylPlayer con il nome del brano "Bohemian Rhapsody"
// TODO: Crea un VinylAdapter che racchiuda il lettore di vinili
// TODO: Memorizza l'adattatore in una variabile di tipo AudioSource
// TODO: Chiama playAudio() sulla tua sorgente audio e stampa il risultato
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniLibrerie e importazioniIntroduzione alla programmazione orientata agli oggettiClassi e oggettiLa parola chiave thisMetodiVariabili di istanzaFondamenti dei costruttoriRiepilogo - Calcolatrice semplice4Sicurezza dei valori null
Introduzione alla sicurezza dei valori nullNullable e non nullableGli operatori ? e !La keyword late e la sicurezza dei valori nullOperatori null-awareSicurezza dei valori null nelle classiRiepilogo - Sistema di profili utente7Classi astratte e interfacce
Classi astratteMetodi astrattiInterfacce in DartInterfacce impliciteImplementare vs estendereInterfacce multipleRiepilogo - Calcolatore di forme10Collezioni e generici
Panoramica di List, Set e MapCollezioni sicure rispetto ai tipiClassi genericheMetodi genericiVincoli sui genericiIterable e IteratorRiepilogo - Archiviazione generica13Concetti avanzati di OOP
Composizione vs ereditarietàMetodi di estensioneClassi chiamabiliClassi sealed (Dart 3)Record (Dart 3)Pattern e matching (3.0)Enum con metodi16Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente2I costruttori in Dart
Costruttore predefinitoCostruttori con nomeListe di inizializzazioneCostruttori costantiCostruttori factoryCostruttori di reindirizzamentoRiepilogo - Crea forme5Incapsulamento
Membri pubblici e privatiConvenzione del prefisso _Visibilità a livello di libreriaApprofondimento su getter e setterNascondimento delle informazioniRiepilogo - Registri degli studenti8Mixin
Introduzione ai MixinCreare MixinUsare più MixinParola chiave on nei MixinMixin vs ereditarietàMixin vs interfacciaRiepilogo - Sistema animale11Metodi speciali
Sovrascrittura di toString()Sovrascrittura di hashCode e ==Interfaccia ComparableMetodo call()Sovrascrittura di noSuchMethodRiepilogo - Collezione personalizzata14Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneSingletonFactoryObserverStrategy3Proprietà delle classi
Membri di istanza e staticiCampi final e constVariabili lateMetodi e campi staticiGetter e setterRiepilogo - Gestore di conti bancari6Ereditarietà
Ereditarietà di baseLa parola chiave superOverride dei metodiL’annotazione @overrideLa parola chiave final per le classiCostruttori ed ereditarietàRiepilogo - Gerarchia dei dipendenti9Polimorfismo
Fondamenti di polimorfismoPolimorfismo tramite interfacceControllo del tipo a runtimeGli operatori is e asParola chiave covariantRiepilogo - Elaboratore di pagamenti12OOP asincrona
Future e async/awaitNozioni di base sugli streamController degli streamCostruttori asincroniAsync nei metodi di classeRiepilogo - Recupero dei dati15Pattern di progettazione Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern RepositoryEsercitati da solo: Compilatore Dart online