CodeGym /Java Blog /Random-IT /Modello di progettazione dell'adattatore
John Squirrels
Livello 41
San Francisco

Modello di progettazione dell'adattatore

Pubblicato nel gruppo Random-IT
CIAO! Oggi toccheremo un nuovo importante argomento: i design pattern . Quali sono questi modelli? Penso che tu debba conoscere l'espressione " non reinventare la ruota ". Nella programmazione, come in molti altri ambiti, ci sono un gran numero di situazioni comuni. Man mano che lo sviluppo del software si è evoluto, sono state create soluzioni già pronte che funzionano per ciascuno di essi. Queste soluzioni sono chiamate modelli di progettazione. Per convenzione, un modello è una soluzione formulata in questo modo: "se hai bisogno di fare X nel tuo programma, allora questo è il modo migliore per farlo". Ci sono molti modelli. A loro è dedicato l'ottimo libro "Head First Design Patterns", con cui dovreste assolutamente familiarizzare. Modello di progettazione dell'adattatore - 2In poche parole, un modello consiste in un problema comune e una soluzione corrispondente che può essere considerata una sorta di standard. Nella lezione di oggi incontreremo uno di questi schemi: Adapter. Il nome dice tutto e hai incontrato gli adattatori molte volte nella vita reale. Alcuni degli adattatori più comuni sono i lettori di schede che hanno molti computer e laptop. Modello di progettazione dell'adattatore - 3Supponiamo di avere una sorta di scheda di memoria. Allora, qual'è il problema? Non sa come interagire con il computer. Non condividono un'interfaccia comune. Il computer ha una porta USB, ma non possiamo inserire la scheda di memoria al suo interno. La scheda non può essere collegata al computer, quindi non possiamo salvare foto, video e altri dati. Un lettore di schede è un adattatore che risolve questo problema. Dopotutto, ha un cavo USB! A differenza della scheda stessa, il lettore di schede può essere collegato al computer. Condividono un'interfaccia comune con il computer: USB. Vediamo come appare in pratica:

public interface USB { 

   void connectWithUsbCable(); 
}
Questa è la nostra interfaccia USB con un solo metodo per la connessione tramite USB.

public class MemoryCard { 

   public void insert() { 
       System.out.println("Memory card successfully inserted!"); 
   } 

   public void copyData() { 
       System.out.println("The data has been copied to the computer!"); 
   } 
}
Questa è la nostra classe che rappresenta la scheda di memoria. Ha già i 2 metodi di cui abbiamo bisogno, ma ecco il problema: non implementa l'interfaccia USB. La scheda non può essere inserita nella porta USB.

public class CardReader implements USB { 

   private MemoryCard memoryCard; 

   public CardReader(MemoryCard memoryCard) { 
       this.memoryCard = memoryCard; 
   } 

   @Override 
   public void connectWithUsbCable() { 
       this.memoryCard.insert(); 
       this.memoryCard.copyData(); 
   } 
}
Ed ecco il nostro adattatore! Cosa fa ilCardReaderclass e cosa lo rende esattamente un adattatore? È tutto semplice. La classe che si sta adattando (MemoryCard) diventa uno dei campi dell'adattatore. Questo ha senso. Quando inseriamo una scheda di memoria all'interno di un lettore di schede nella vita reale, anche questa ne diventa parte. A differenza della scheda di memoria, l'adattatore condivide un'interfaccia con il computer. Ha un cavo USB, cioè può essere collegato ad altri dispositivi tramite USB. Ecco perché la nostra classe CardReader implementa l'interfaccia USB. Ma cosa succede esattamente all'interno di questo metodo? Esattamente quello di cui abbiamo bisogno per accadere! L'adattatore delega il lavoro alla nostra scheda di memoria. In effetti, l'adattatore non fa nulla da solo. Un lettore di schede non ha alcuna funzionalità indipendente. Il suo compito è solo quello di collegare il computer e la scheda di memoria per consentire alla scheda di svolgere il proprio lavoro: copiare i file!connectWithUsbCable()metodo) per soddisfare le "esigenze" della scheda di memoria. Creiamo un programma client che simulerà una persona che vuole copiare i dati da una scheda di memoria:

public class Main { 

   public static void main(String[] args) { 

       USB cardReader = new CardReader(new MemoryCard()); 
       cardReader.connectWithUsbCable(); 
   } 
}
Quindi cosa abbiamo ottenuto? Uscita console:

Memory card successfully inserted! 
The data has been copied to the computer!
Eccellente. Abbiamo raggiunto il nostro obiettivo! Di seguito è riportato un collegamento a un video con informazioni sul modello Adapter:

Classi astratte Reader e Writer

Ora torneremo alla nostra attività preferita: conoscere un paio di nuove classi per lavorare con input e output :) Mi chiedo quante ne abbiamo già imparate. Oggi parleremo delle classi Reader e Writer. Perché proprio quelle classi? Perché sono correlati alla nostra sezione precedente sugli adattatori. Esaminiamoli più in dettaglio. Inizieremo con  Reader. Readerè una classe astratta, quindi non saremo in grado di creare oggetti in modo esplicito.   Ma in realtà lo conosci già! Dopotutto, conosci bene le classi BufferedReadere InputStreamReader, che sono i suoi discendenti :)

public class BufferedReader extends Reader { 
… 
} 

public class InputStreamReader extends Reader { 
… 
}
La InputStreamReaderclasse è un adattatore classico. Come probabilmente ricorderai, possiamo passare un InputStreamoggetto al suo costruttore. Per fare questo, di solito usiamo la System.invariabile:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
Ma cosa InputStreamReaderfa? Come ogni adattatore, converte un'interfaccia in un'altra.  In questo caso, l' InputStreaminterfaccia all'interfaccia Reader. Inizialmente, abbiamo la InputStreamclasse. Funziona bene, ma puoi usarlo solo per leggere singoli byte. Inoltre, abbiamo una Readerclasse astratta. Ha alcune funzionalità molto utili: sa leggere i caratteri! Abbiamo certamente bisogno di questa capacità. Ma qui affrontiamo il classico problema solitamente risolto dagli adattatori: interfacce incompatibili. Che cosa significa? Diamo un'occhiata alla documentazione di Oracle. Ecco i metodi della InputStreamclasse. Modello di progettazione dell'adattatore - 4Un insieme di metodi è esattamente ciò che è un'interfaccia. Come puoi vedere, questa classe ha aread()metodo (poche varianti, in effetti), ma può solo leggere byte: singoli byte o più byte utilizzando un buffer. Ma questa opzione non è adatta a noi: vogliamo leggere i caratteri. Abbiamo bisogno della funzionalità che è già implementata nella Readerclasse astratta . Possiamo anche vedere questo nella documentazione. Modello di progettazione dell'adattatore - 5Tuttavia, le interfacce InputStreame  Readernon sono compatibili! Come puoi vedere, ogni implementazione del read()metodo ha parametri e valori restituiti diversi. Ed è qui che ci serve InputStreamReader! Agirà da adattatore tra le nostre classi. Come nell'esempio con il lettore di schede, che abbiamo considerato sopra, mettiamo un'istanza della classe adattata "all'interno" della classe dell'adattatore, cioè ne passiamo una al suo costruttore. Nell'esempio precedente, inseriamo un MemoryCardoggetto all'interno di CardReader. Ora stiamo passando un InputStream oggetto al InputStreamReadercostruttore! Usiamo la nostra System.invariabile familiare come InputStream:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
E in effetti, guardando la documentazione di InputStreamReader, possiamo vedere che l'adattamento è riuscito :) Ora abbiamo a nostra disposizione metodi per leggere i caratteri. Modello di progettazione dell'adattatore - 6E sebbene il nostro System.inoggetto (il flusso associato alla tastiera) inizialmente non lo consentisse, i creatori del linguaggio hanno risolto questo problema implementando il modello dell'adattatore. La Readerclasse astratta, come la maggior parte delle classi I/O, ha un fratello gemello —  Writer. Ha lo stesso grande vantaggio di  Reader : fornisce una comoda interfaccia per lavorare con i personaggi. Con i flussi di output, il problema e la sua soluzione hanno lo stesso aspetto dei flussi di input. C'è una OutputStreamclasse che può scrivere solo byte, c'è aWriterclasse astratta che sa come lavorare con i caratteri e ci sono due interfacce incompatibili. Questo problema è ancora una volta risolto dal modello dell'adattatore. Usiamo la OutputStreamWriterclasse per adattare facilmente le due interfacce delle classi Writer e l'  OutputStream una all'altra. Dopo aver passato un OutputStreamflusso di byte al costruttore, possiamo usare an OutputStreamWriterper scrivere caratteri anziché byte!

import java.io.*; 

public class Main { 

   public static void main(String[] args) throws IOException { 

       OutputStreamWriter streamWriter = new OutputStreamWriter(new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt")); 
       streamWriter.write(32144); 
       streamWriter.close();
   } 
}
Abbiamo scritto il carattere con il codice 32144 (綐) nel nostro file, eliminando la necessità di lavorare con i byte :) Per oggi è tutto. Ci vediamo alle prossime lezioni! :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION