Menu
Coddy logo textTech

Pattern Adapter

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 97 di 104.

Il pattern Adapter consente a interfacce incompatibili di lavorare insieme. Funge da ponte tra due classi, convertendo l'interfaccia di una classe in un'interfaccia prevista dai client. È particolarmente utile quando si integra codice legacy o librerie di terze parti che non corrispondono all'interfaccia del sistema.

Immagina di avere una classe esistente che fa ciò di cui hai bisogno, ma la sua interfaccia non corrisponde a ciò che il tuo codice si aspetta. Invece di modificare uno dei due lati, crei un adattatore che avvolge la classe esistente e traduce le chiamate:

#include <iostream>
#include <string>

// Classe esistente con un'interfaccia incompatibile
class LegacyPrinter {
public:
    void printMessage(const std::string& msg) {
        std::cout << "Legacy: " << msg << "\n";
    }
};

// Interfaccia di destinazione prevista dal client
class Printer {
public:
    virtual void print(const std::string& text) = 0;
    virtual ~Printer() = default;
};

// L'adapter incapsula LegacyPrinter e implementa l'interfaccia Printer
class PrinterAdapter : public Printer {
    LegacyPrinter& legacy;
public:
    PrinterAdapter(LegacyPrinter& lp) : legacy(lp) {}
    
    void print(const std::string& text) override {
        legacy.printMessage(text);  // Adatta la chiamata
    }
};

int main() {
    LegacyPrinter oldPrinter;
    PrinterAdapter adapter(oldPrinter);
    
    // Il client usa l'interfaccia prevista
    adapter.print("Hello World");
}

L’adattatore mantiene un riferimento a LegacyPrinter e implementa l’interfaccia Printer. Quando viene chiamato print(), delega a printMessage(). Il codice client lavora con l’interfaccia Printer senza conoscere l’implementazione legacy sottostante.

Usa 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.

challenge icon

Sfida

Facile

Costruiamo un sistema di adattatore per lettore multimediale che collega interfacce diverse di librerie audio. Immagina di integrare una libreria audio legacy in un'applicazione moderna di riproduzione multimediale: la vecchia libreria funziona perfettamente, ma la sua interfaccia non corrisponde a ciò che il tuo lettore si aspetta. È proprio qui che il pattern Adapter dà il meglio di sé.

Organizzerai il codice in quattro file:

  • MediaPlayer.h: definisci l'interfaccia di destinazione che il tuo moderno lettore multimediale si aspetta.

    Crea una classe astratta MediaPlayer con questi metodi virtuali puri:

    • play(const std::string& filename): riproduce il file specificato
    • stop(): interrompe la riproduzione
    • setVolume(int level): imposta il volume (0-100)

    Includi un distruttore virtuale.

  • LegacyAudioLib.h: crea la libreria audio "legacy" esistente, con un'interfaccia incompatibile.

    La tua classe LegacyAudioLib rappresenta una vecchia libreria che funziona in modo diverso da quello che il tuo lettore si aspetta. Dovrebbe avere:

    • loadAudio(const std::string& path): stampa Legacy: Loading [path]
    • startPlayback(): stampa Legacy: Playback started
    • stopPlayback(): stampa Legacy: Playback stopped
    • adjustVolume(double percentage): accetta un decimale (da 0.0 a 1.0) e stampa Legacy: Volume set to [percentage] (mostra il valore decimale)
  • AudioAdapter.h: crea l'adattatore che collega le due interfacce.

    La tua classe AudioAdapter dovrebbe ereditare da MediaPlayer e mantenere un riferimento a un oggetto LegacyAudioLib. L'adattatore traduce le chiamate dall'interfaccia moderna a quella legacy:

    • play() dovrebbe chiamare sia loadAudio() sia startPlayback() sulla libreria legacy
    • stop() dovrebbe delegare a stopPlayback()
    • setVolume() riceve un intero (0-100), ma la libreria legacy si aspetta un decimale (0.0-1.0), quindi dovrai convertirlo
  • main.cpp: mostra l'adattatore in azione.

    Leggi due input:

    1. Un nome di file da riprodurre (stringa)
    2. Un livello del volume (intero, 0-100)

    Crea un'istanza di LegacyAudioLib e un AudioAdapter che la avvolga. Poi usa l'adattatore tramite l'interfaccia MediaPlayer (memorizzalo come puntatore a MediaPlayer) per:

    1. Impostare il volume al livello specificato dall'input
    2. Riprodurre il nome di file specificato dall'input
    3. Interrompere la riproduzione

Ad esempio, con gli input song.mp3 e 75:

Legacy: Volume set to 0.75
Legacy: Loading song.mp3
Legacy: Playback started
Legacy: Playback stopped

Con gli input podcast.wav e 50:

Legacy: Volume set to 0.5
Legacy: Loading podcast.wav
Legacy: Playback started
Legacy: Playback stopped

Nota che il codice client usa interamente l'interfaccia MediaPlayer. Non sa che sotto, a svolgere il lavoro vero e proprio, c'è una libreria legacy. L'adattatore gestisce tutta la traduzione, compresa la conversione del volume da intero a decimale. Questa è l'essenza del pattern Adapter: far funzionare insieme interfacce incompatibili senza modificare nessuna delle due.

Provalo tu

#include <iostream>
#include <string>
#include "MediaPlayer.h"
#include "LegacyAudioLib.h"
#include "AudioAdapter.h"

using namespace std;

int main() {
    // Leggi gli input
    string filename;
    int volumeLevel;
    cin >> filename;
    cin >> volumeLevel;
    
    // TODO: Crea un'istanza di LegacyAudioLib
    
    // TODO: Crea un AudioAdapter che incapsuli la libreria legacy
    
    // TODO: Memorizza l'adapter come puntatore a MediaPlayer
    
    // TODO: Usa l'interfaccia MediaPlayer per:
    // 1. Impostare il volume al livello specificato nell'input
    // 2. Riprodurre il file specificato dal nome nell'input
    // 3. Interrompere la riproduzione
    
    return 0;
}
quiz iconMettiti alla prova

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

Esercitati da solo: Compilatore C++ online