CodeGym /Blog Java /Aleatoriu /Model de design adaptor
John Squirrels
Nivel
San Francisco

Model de design adaptor

Publicat în grup
Bună! Astăzi vom atinge un subiect nou important: modelele de design . Care sunt aceste modele? Cred că trebuie să cunoașteți expresia „ nu reinventați roata ”. În programare, ca și în multe alte domenii, există un număr mare de situații comune. Pe măsură ce dezvoltarea software-ului a evoluat, au fost create soluții gata făcute care funcționează pentru fiecare dintre ele. Aceste soluții se numesc modele de design. Prin convenție, un model este o soluție formulată astfel: „dacă trebuie să faci X în programul tău, atunci acesta este cel mai bun mod de a face asta”. Există o mulțime de modele. Le este dedicată excelenta carte „Head First Design Patterns”, cu care cu siguranță ar trebui să vă familiarizați. Model de design adaptor - 2Pe scurt, un model constă dintr-o problemă comună și o soluție corespunzătoare care poate fi considerată un fel de standard. În lecția de astăzi, vom întâlni unul dintre aceste modele: Adaptor. Numele lui spune totul și ați întâlnit adaptoare de multe ori în viața reală. Unele dintre cele mai comune adaptoare sunt cititoarele de carduri pe care le au multe computere și laptop-uri. Model de design adaptor - 3Să presupunem că avem un fel de card de memorie. Deci care este problema? Nu știe cum să interacționeze cu computerul. Nu au o interfață comună. Computerul are un port USB, dar nu putem introduce cardul de memorie în el. Cardul nu poate fi conectat la computer, așa că nu ne putem salva fotografiile, videoclipurile și alte date. Un cititor de carduri este un adaptor care rezolvă această problemă. La urma urmei, are un cablu USB! Spre deosebire de cardul în sine, cititorul de carduri poate fi conectat la computer. Au o interfață comună cu computerul: USB. Să vedem cum arată asta în practică:

public interface USB { 

   void connectWithUsbCable(); 
}
Aceasta este interfața noastră USB cu o singură metodă de conectare prin 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!"); 
   } 
}
Aceasta este clasa noastră care reprezintă cardul de memorie. Are deja cele 2 metode de care avem nevoie, dar iată problema: nu implementează interfața USB. Cardul nu poate fi introdus în portul 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(); 
   } 
}
Și iată adaptorul nostru! Ce faceCardReaderclasa face și ce anume îl face un adaptor? Totul este simplu. Clasa care se adaptează (MemoryCard) devine unul dintre câmpurile adaptorului. Are sens. Când punem un card de memorie în interiorul unui cititor de carduri în viața reală, acesta devine și o parte a acestuia. Spre deosebire de cardul de memorie, adaptorul partajează o interfață cu computerul. Are cablu USB, adică poate fi conectat la alte dispozitive prin USB. De aceea, clasa noastră CardReader implementează interfața USB. Dar ce se întâmplă exact în cadrul acestei metode? Exact ceea ce trebuie să se întâmple! Adaptorul deleagă munca pe cardul nostru de memorie. Într-adevăr, adaptorul nu face nimic de la sine. Un cititor de carduri nu are nicio funcționalitate independentă. Sarcina sa este doar de a conecta computerul și cardul de memorie pentru a permite cardului să-și facă treaba - copierea fișierelor!connectWithUsbCable()metoda) pentru a satisface „nevoile” cardului de memorie. Să creăm un program client care va simula o persoană care dorește să copieze date de pe un card de memorie:

public class Main { 

   public static void main(String[] args) { 

       USB cardReader = new CardReader(new MemoryCard()); 
       cardReader.connectWithUsbCable(); 
   } 
}
Deci ce am primit? Ieșire din consolă:

Memory card successfully inserted! 
The data has been copied to the computer!
Excelent. Ne-am atins obiectivul! Iată un link către un videoclip cu informații despre modelul adaptorului:

Cursuri de abstracte pentru cititori și scriitori

Acum ne vom întoarce la activitatea noastră preferată: a afla despre câteva clase noi pentru lucrul cu input și output :) Mă întreb despre câte am învățat deja. Astăzi vom vorbi despre clasele Reader și Writer. De ce anume acele clase? Pentru că sunt legate de secțiunea noastră anterioară despre adaptoare. Să le examinăm mai detaliat. Vom începe cu  Reader. Readereste o clasă abstractă, deci nu vom putea crea obiecte în mod explicit.   Dar de fapt ești deja familiarizat cu el! La urma urmei, ești bine familiarizat cu clasele BufferedReaderși InputStreamReader, care sunt descendenții lui :)

public class BufferedReader extends Reader { 
… 
} 

public class InputStreamReader extends Reader { 
… 
}
Clasa InputStreamReadereste un adaptor clasic. După cum probabil vă amintiți, putem transmite un InputStreamobiect constructorului său. Pentru a face acest lucru, folosim de obicei System.invariabila:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
Dar ce InputStreamReaderface? Ca orice adaptor, convertește o interfață la alta.  În acest caz, InputStreaminterfața cu Readerinterfața. Inițial, avem InputStreamclasa. Funcționează bine, dar îl puteți folosi doar pentru a citi octeți individuali. În plus, avem o Readerclasă abstractă. Are unele funcționalități foarte utile — știe să citească caracterele! Cu siguranță avem nevoie de această abilitate. Dar aici ne confruntăm cu problema clasică rezolvată de obicei de adaptoare – interfețe incompatibile. Ce înseamnă asta? Să aruncăm o privire la documentația Oracle. Iată metodele clasei InputStream. Model de design adaptor - 4Un set de metode este exact ceea ce este o interfață. După cum puteți vedea, această clasă are unread()metoda (câteva variante, de fapt), dar poate citi doar octeți: fie octeți individuali, fie mai mulți octeți folosind un buffer. Dar această opțiune nu ne convine – vrem să citim caractere. Avem nevoie de funcționalitatea care este deja implementată în Readerclasa abstractă . Putem vedea acest lucru și în documentație. Model de design adaptor - 5Cu toate acestea, interfețele InputStreamși  Readersunt incompatibile! După cum puteți vedea, fiecare implementare a read()metodei are parametri și valori returnate diferiți. Și aici avem nevoie InputStreamReader! Va acționa ca un adaptor între clasele noastre. La fel ca în exemplul cu cititorul de carduri, pe care l-am considerat mai sus, punem o instanță a clasei care se adaptează „în interiorul” clasei adaptor, adică trecem una constructorului acesteia. În exemplul anterior, punem un MemoryCardobiect în interiorul CardReader. Acum transmitem un InputStream obiect constructorului InputStreamReader! Folosim System.invariabila noastră familiară ca InputStream:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
Și într-adevăr, uitându-ne la documentația pentru InputStreamReader, putem observa că adaptarea a reușit :) Acum avem la dispoziție metode de citire a personajelor. Model de design adaptor - 6Și deși obiectul nostru System.in(fluxul legat de tastatură) nu a permis inițial acest lucru, creatorii limbii au rezolvat această problemă prin implementarea modelului adaptorului. Clasa Readerabstractă, ca majoritatea claselor I/O, are un frate geamăn —  Writer. Are același mare avantaj ca  Reader - oferă o interfață convenabilă pentru lucrul cu personajele. În cazul fluxurilor de ieșire, problema și soluția ei arată la fel ca și în cazul fluxurilor de intrare. Există o OutputStreamclasă care poate scrie doar octeți, există oWriterclasă abstractă care știe să lucreze cu personaje și există două interfețe incompatibile. Această problemă este din nou rezolvată de modelul adaptorului. Folosim OutputStreamWriterclasa pentru a adapta cu ușurință cele două interfețe ale claselor Writer și una  OutputStream la alta. După transmiterea unui OutputStreamflux de octeți către constructor, putem folosi un OutputStreamWriterpentru a scrie caractere mai degrabă decât octeți!

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();
   } 
}
Am scris caracterul cu codul 32144 (綐) în fișierul nostru, eliminând nevoia de a lucra cu octeți :) Asta e tot pentru astăzi. Ne vedem la următoarele lecții! :)
Comentarii
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION