CodeGym /Java-blogg /Tilfeldig /Adapterdesignmønster
John Squirrels
Nivå
San Francisco

Adapterdesignmønster

Publisert i gruppen
Hei! I dag skal vi berøre et viktig nytt emne: designmønstre . Hva er disse mønstrene? Jeg tror du må kjenne til uttrykket " ikke oppfinn hjulet på nytt ". I programmering, som på mange andre områder, er det et stort antall vanlige situasjoner. Etter hvert som programvareutviklingen har utviklet seg, er det laget ferdige løsninger som fungerer for hver av dem. Disse løsningene kalles designmønstre. Etter konvensjon er et mønster en løsning formulert slik: "hvis du trenger å gjøre X i programmet ditt, så er dette den beste måten å gjøre det på". Det er mange mønstre. Den utmerkede boken "Head First Design Patterns", som du definitivt bør bli kjent med, er dedikert til dem. Adapterdesignmønster - 2Kort sagt består et mønster av et felles problem og en tilsvarende løsning som kan betraktes som en slags standard. I dagens leksjon vil vi møte et av disse mønstrene: Adapter. Navnet sier alt, og du har møtt adaptere mange ganger i det virkelige liv. Noen av de vanligste adapterene er kortleserne som mange datamaskiner og bærbare datamaskiner har. Adapterdesignmønster - 3Anta at vi har et slags minnekort. Så hva er problemet? Den vet ikke hvordan den skal samhandle med datamaskinen. De deler ikke et felles grensesnitt. Datamaskinen har en USB-port, men vi kan ikke sette inn minnekortet i den. Kortet kan ikke kobles til datamaskinen, så vi kan ikke lagre bildene, videoene og andre dataene våre. En kortleser er en adapter som løser dette problemet. Tross alt har den en USB-kabel! I motsetning til selve kortet, kan kortleseren kobles til datamaskinen. De deler et felles grensesnitt med datamaskinen: USB. La oss se hvordan dette ser ut i praksis:

public interface USB { 

   void connectWithUsbCable(); 
}
Dette er vårt USB-grensesnitt med bare én metode for tilkobling via 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!"); 
   } 
}
Dette er vår klasse som representerer minnekortet. Den har allerede de 2 metodene vi trenger, men her er problemet: Den implementerer ikke USB-grensesnittet. Kortet kan ikke settes inn i USB-porten.

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(); 
   } 
}
Og her er adapteren vår! Hva gjørCardReaderklasse gjøre og hva gjør det til en adapter? Det hele er enkelt. Klassen som tilpasses (MemoryCard) blir et av adapterens felt. Dette gir mening. Når vi setter et minnekort i en kortleser i det virkelige liv, blir det også en del av det. I motsetning til minnekortet deler adapteren et grensesnitt med datamaskinen. Den har en USB-kabel, dvs. den kan kobles til andre enheter via USB. Det er derfor vår CardReader-klasse implementerer USB-grensesnittet. Men hva skjer egentlig i denne metoden? Akkurat det vi trenger for å skje! Adapteren delegerer arbeidet til minnekortet vårt. Faktisk gjør ikke adapteren noe selv. En kortleser har ingen uavhengig funksjonalitet. Dens jobb er bare å koble sammen datamaskinen og minnekortet for å la kortet gjøre jobben sin - kopiere filer!connectWithUsbCable()metode) for å dekke minnekortets "behov". La oss lage et klientprogram som vil simulere en person som ønsker å kopiere data fra et minnekort:

public class Main { 

   public static void main(String[] args) { 

       USB cardReader = new CardReader(new MemoryCard()); 
       cardReader.connectWithUsbCable(); 
   } 
}
Så hva fikk vi? Konsoll utgang:

Memory card successfully inserted! 
The data has been copied to the computer!
Utmerket. Vi nådde målet vårt! Her er en lenke til en video med informasjon om adaptermønsteret:

Leser og forfatter abstrakt klasser

Nå skal vi gå tilbake til favorittaktiviteten vår: lære om et par nye klasser for arbeid med input og output :) Jeg lurer på hvor mange vi allerede har lært om. I dag skal vi snakke om Reader og Writerklasser. Hvorfor akkurat disse klassene? Fordi de er relatert til vår forrige del om adaptere. La oss undersøke dem mer detaljert. Vi begynner med  Reader. Readerer en abstrakt klasse, så vi vil ikke kunne lage objekter eksplisitt.   Men du er faktisk allerede kjent med det! Tross alt er du godt kjent med klassene BufferedReaderog InputStreamReader, som er dens etterkommere :)

public class BufferedReader extends Reader { 
… 
} 

public class InputStreamReader extends Reader { 
… 
}
Klassen InputStreamReaderer en klassisk adapter. Som du sikkert husker, kan vi sende et InputStreamobjekt til konstruktøren. For å gjøre dette bruker vi vanligvis variabelen System.in:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
Men hva InputStreamReadergjør? Som alle adaptere konverterer den ett grensesnitt til et annet.  I dette tilfellet, grensesnittet InputStreamtil Readergrensesnittet. I første omgang har vi InputStreamklassen. Det fungerer bra, men du kan bare bruke det til å lese individuelle byte. I tillegg har vi en Readerabstrakt klasse. Den har noen veldig nyttige funksjoner - den vet hvordan den skal lese tegn! Vi trenger absolutt denne evnen. Men her står vi overfor det klassiske problemet som vanligvis løses av adaptere – inkompatible grensesnitt. Hva betyr det? La oss ta en titt på Oracle-dokumentasjonen. Her er metodene til klassen InputStream. Adapterdesignmønster - 4Et sett med metoder er nøyaktig hva et grensesnitt er. Som du kan se, har denne klassen enread()metode (faktisk noen få varianter), men den kan bare lese byte: enten individuelle byte eller flere byte ved å bruke en buffer. Men dette alternativet passer ikke oss - vi vil lese karakterer. Vi trenger funksjonaliteten som allerede er implementert i Readerabstraktklassen . Dette kan vi også se i dokumentasjonen. Adapterdesignmønster - 5Men grensesnittene InputStreamog  Readerer inkompatible! Som du kan se, har hver implementering av read()metoden forskjellige parametere og returverdier. Og det er her vi trenger InputStreamReader! Den vil fungere som en adapter mellom klassene våre. Som i eksempelet med kortleseren, som vi vurderte ovenfor, legger vi en forekomst av at klassen er tilpasset "inne" i adapterklassen, dvs. vi sender en til dens konstruktør. I forrige eksempel la vi et MemoryCardobjekt inni CardReader. Nå sender vi et InputStream objekt til InputStreamReaderkonstruktøren! Vi bruker vår kjente System.invariabel som InputStream:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
Og faktisk, ser vi på dokumentasjonen for InputStreamReader, kan vi se at tilpasningen lyktes :) Nå har vi metoder for å lese karakterer til vår disposisjon. Adapterdesignmønster - 6Og selv om objektet vårt System.in(strømmen bundet til tastaturet) i utgangspunktet ikke tillot dette, løste språkets skapere dette problemet ved å implementere adaptermønsteret. Den Readerabstrakte klassen, som de fleste I/O-klasser, har en tvillingbror —  Writer. Den har den samme store fordelen som  Reader — den gir et praktisk grensesnitt for å jobbe med karakterer. Med utgangsstrømmer ser problemet og løsningen det samme ut som med inngangsstrømmer. Det er en OutputStreamklasse som bare kan skrive bytes, det er enWriterabstrakt klasse som vet hvordan man jobber med tegn, og det er to inkompatible grensesnitt. Dette problemet er igjen løst av adaptermønsteret. Vi bruker OutputStreamWriterklassen for enkelt å tilpasse de to grensesnittene til Writer og  OutputStream klassene til hverandre. Etter å ha sendt en OutputStreambytestrøm til konstruktøren, kan vi bruke en OutputStreamWritertil å skrive tegn i stedet for 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();
   } 
}
Vi skrev tegnet med kode 32144 (綐) til filen vår, og eliminerte behovet for å jobbe med bytes :) Det var det for i dag. Vi sees i neste leksjoner! :)
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION