JavaRush /Java Blog /Random-IT /Adattatore modello di progettazione

Adattatore modello di progettazione

Pubblicato nel gruppo Random-IT
Ciao! Oggi toccheremo un nuovo argomento importante: i modelli o, in altre parole, i modelli di design . Cosa sono i modelli? Penso che tu conosca l'espressione "non reinventare la ruota". Nella programmazione, come in molti altri settori, esistono numerose situazioni tipiche. Per ciascuno di essi, nel processo di sviluppo della programmazione, sono state create soluzioni di lavoro già pronte. Questi sono modelli di progettazione. Relativamente parlando, un pattern è un certo esempio che offre una soluzione a una situazione del tipo: “se il tuo programma ha bisogno di fare qualcosa, come farlo al meglio”. Ci sono molti modelli, a loro è dedicato un ottimo libro "Studying Design Patterns", che dovresti assolutamente leggere. Modello di progettazione "Adattatore" - 2Per dirla nel modo più breve possibile, un modello consiste in un problema comune e nella sua soluzione, che può già essere considerata una sorta di standard. Nella lezione di oggi faremo conoscenza con uno di questi modelli chiamato "Adattatore". Il suo nome è eloquente e ti sei imbattuto negli adattatori nella vita reale più di una volta. Uno degli adattatori più comuni sono i lettori di carte, di cui sono dotati molti computer e laptop. Modello di progettazione dell'adattatore - 3Immagina di avere una sorta di scheda di memoria. Qual è il problema? Il fatto è che non sa come interagire con un computer. Non hanno un'interfaccia comune. Il computer è dotato di un connettore USB, ma non è possibile inserirvi una scheda di memoria. La scheda non può essere inserita nel computer, per cui non saremo in grado di salvare le nostre foto, video e altri dati. Il lettore di schede è un adattatore che risolve questo problema. Dopotutto, ha un cavo USB! A differenza della carta stessa, il lettore di carte può essere inserito in un computer. Hanno un'interfaccia comune con il computer: USB. Vediamo come sarebbe con un esempio:
public interface USB {

   void connectWithUsbCable();
}
Questa è la nostra interfaccia USB e l'unico metodo è inserire il cavo USB:
public class MemoryCard {

   public void insert() {
       System.out.println("Карта памяти успешно вставлена!");
   }

   public void copyData() {
       System.out.println("Данные скопированы на компьютер!");
   }
}
Questa è la nostra classe che implementa la mappa 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 nello slot 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 la classeCardReader e perché è un adattatore? È semplice. La classe da adattare (mappa di memoria) diventa uno dei campi dell'adattatore. Questo è logico, perché nella vita reale inseriamo anche una carta all'interno del lettore di carte, e anch'essa ne diventa parte. A differenza di una scheda di memoria, l'adattatore ha un'interfaccia comune con il computer. Ha un cavo USB, il che significa che può connettersi ad altri dispositivi tramite USB. Pertanto, nel programma, la nostra classe CardReaderimplementa l'interfaccia USB. Ma cosa succede all’interno di questo metodo? E succede esattamente ciò di cui abbiamo bisogno! L'adattatore delega il lavoro alla nostra scheda di memoria. Dopotutto l'adattatore in sé non fa nulla, il lettore di carte non ha alcuna funzionalità indipendente. Il suo compito è solo quello di collegare il computer e la scheda di memoria in modo che la scheda possa svolgere il suo lavoro e copiare file! Il nostro adattatore gli consente di farlo fornendo la propria interfaccia (metodo connectWithUsbCable()) per le "esigenze" della scheda di memoria. Creiamo una sorta di programma client che simulerà una persona che desidera copiare dati da una scheda di memoria:
public class Main {

   public static void main(String[] args) {

       USB cardReader = new CardReader(new MemoryCard());
       cardReader.connectWithUsbCable();

   }
}
Cosa abbiamo ottenuto come risultato? Uscita console:
Карта памяти успешно вставлена!
Данные скопированы на компьютер!
Ottimo, il nostro compito è stato completato con successo! Di seguito sono riportati alcuni collegamenti aggiuntivi con informazioni sul modello dell'adattatore:

Classi astratte Reader e Writer

Ora torneremo al nostro passatempo preferito: impareremo un paio di nuove lezioni per lavorare con input e output :) Quante di queste abbiamo già imparato, mi chiedo? Oggi parleremo di classi Readere Writer. Perché su di loro? Perché questo sarà correlato alla nostra sezione precedente: adattatori. Diamo un'occhiata a loro in modo più dettagliato. Cominciamo con Reader'a. Readerè una classe astratta, quindi non saremo in grado di creare esplicitamente i suoi oggetti. Ma in realtà lo conosci già! Dopotutto, le classi che conosci bene BufferedReadersono InputStreamReaderi suoi eredi :)
public class BufferedReader extends Reader {}

public class InputStreamReader extends Reader {}
Quindi, una classe InputStreamReaderè un adattatore classico . Come probabilmente ricorderete, possiamo passare un oggetto al suo costruttore InputStream. Molto spesso usiamo una variabile per questo System.in:
public static void main(String[] args) {

   InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
Che cosa fa InputStreamReader? Come qualsiasi adattatore, converte un'interfaccia in un'altra. In questo caso, l'interfaccia InputStream'a all'interfaccia Reader'a. Inizialmente avevamo una lezione InputStream. Funziona bene, ma può leggere solo singoli byte. Inoltre, abbiamo una classe astratta Reader. Ha funzionalità eccellenti di cui abbiamo davvero bisogno: può leggere i caratteri! Naturalmente abbiamo davvero bisogno di questa opportunità. Ma qui ci troviamo di fronte a un classico problema che di solito gli adattatori risolvono: l'incompatibilità dell'interfaccia. Come si manifesta? Diamo un'occhiata direttamente alla documentazione Oracle. Ecco i metodi della classe InputStream. Modello di progettazione "Adattatore" - 4Un insieme di metodi è un'interfaccia. Come puoi vedere, read()questa classe ha un metodo (anche in diverse versioni), ma può leggere solo byte: singoli byte o più byte utilizzando un buffer. Questa opzione non è adatta a noi: vogliamo leggere i caratteri. La funzionalità di cui abbiamo bisogno è già implementata nella classe astrattaReader . Questo può essere visto anche nella documentazione. Modello di progettazione dell'adattatore - 5Tuttavia, le interfacce InputStream"a" e "a" sono incompatibili! ReaderCome puoi vedere, in tutte le implementazioni del metodo, read()sia i parametri passati che i valori restituiti differiscono. Ed è qui che ne abbiamo bisogno InputStreamReader! Agirà come adattatore tra le nostre classi. Come nell'esempio del lettore di carte, che abbiamo visto sopra, passiamo l'oggetto della classe “adattata” “internamente”, cioè al costruttore della classe adattatore. Nell'esempio precedente, abbiamo passato un oggetto MemoryCardall'interno di CardReader. Ora passiamo l'oggetto InputStreamal costruttore InputStreamReader! Come qualità InputStreamutilizziamo la variabile già familiare System.in:
public static void main(String[] args) {

   InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
E infatti: guardando la documentazione InputStreamReadervedremo che l'“adattamento” ha avuto successo :) Ora abbiamo a nostra disposizione metodi che ci permettono di leggere i caratteri. Modello di progettazione dell'adattatore - 6E sebbene inizialmente il nostro oggetto System.in(un thread associato alla tastiera) non lo consentisse, creando il pattern Adapter , i creatori del linguaggio hanno risolto questo problema. La classe astratta Reader, come la maggior parte delle classi I/O, ha un fratello gemello: Writer. Ha lo stesso grande vantaggio Reader: fornisce un'interfaccia comoda per lavorare con i simboli. Con i flussi di output, il problema e la sua soluzione sembrano gli stessi che nel caso dei flussi di input. Esiste una classe OutputStreamche può scrivere solo byte; Esiste una classe astratta Writerche può funzionare con i simboli e esistono due interfacce incompatibili. Anche questo problema viene risolto con successo dal modello Adapter. Usando una classe, OutputStreamWriterpossiamo facilmente “adattare” le interfacce di due classi Writertra OutputStreamloro. E, avendo ricevuto un flusso di byte OutputStreamnel costruttore, con l'aiuto OutputStreamWriterpossiamo comunque scrivere caratteri, non 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 un carattere con il codice 32144 - 綐 nel nostro file, eliminando così 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