Szia! Ma egy fontos új témát fogunk érinteni: a tervezési mintákat . Mik ezek a minták? Szerintem ismerned kell a " ne találd fel újra a kereket " kifejezést. A programozásban, mint sok más területen, számos gyakori helyzet adódik. A szoftverfejlesztés fejlődésével mindegyikhez készültek működő kész megoldások. Ezeket a megoldásokat tervezési mintáknak nevezzük. Megállapodás szerint a minta valamilyen megoldás, amely így van megfogalmazva: "ha X-et kell tennie a programban, akkor ez a legjobb módja annak". Rengeteg minta van. Nekik készült a kiváló "Head First Design Patterns" könyv, amelyet mindenképpen érdemes megismerned.
Tömören fogalmazva, egy minta egy közös problémából és egy megfelelő megoldásból áll, amely egyfajta szabványnak tekinthető. A mai leckében a következő minták egyikével fogunk találkozni: Adapter. A neve mindent elárul, és a való életben is sokszor találkozott már adapterekkel. A leggyakoribb adapterek a kártyaolvasók, amelyek sok számítógépen és laptopon megtalálhatók.
Tegyük fel, hogy van valamilyen memóriakártyánk. Tehát mi a probléma? Nem tudja, hogyan kommunikáljon a számítógéppel. Nincs közös felületük. A számítógép USB porttal rendelkezik, de nem tudjuk belehelyezni a memóriakártyát. A kártya nem csatlakoztatható a számítógéphez, így fotóinkat, videóinkat és egyéb adatainkat nem tudjuk elmenteni. A kártyaolvasó egy adapter, amely megoldja ezt a problémát. Elvégre USB kábel van hozzá! Magával a kártyával ellentétben a kártyaolvasó csatlakoztatható a számítógéphez. Közös interfészük van a számítógéppel: USB. Lássuk, hogyan is néz ki ez a gyakorlatban:
Egy interfész pontosan a metódusok halmaza. Amint látja, ennek az osztálynak a
azonban nem kompatibilisek! Amint látható, a metódus minden implementációja eltérő paraméterekkel és visszatérési értékekkel rendelkezik. És itt van szükségünk ! Adapterként fog működni az osztályaink között.
És bár az
![Adapter tervezési minta - 2](https://cdn.codegym.cc/images/article/6594b8f4-4388-480b-b09f-ad56d99661ba/512.jpeg)
![Adapter tervezési minta - 3](https://cdn.codegym.cc/images/article/18ae3c86-996a-4263-af73-993c26442b76/800.jpeg)
public interface USB {
void connectWithUsbCable();
}
Ez a mi USB-interfészünk, amely egyetlen USB-csatlakozási móddal rendelkezik.
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!");
}
}
Ez a mi osztályunk, amely a memóriakártyát képviseli. Már megvan a 2 módszer, amire szükségünk van, de itt van a probléma: Nem valósítja meg az USB interfészt. A kártya nem helyezhető be az USB-portba.
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();
}
}
És itt az adapterünk! Mit csinál aCardReader
osztály dolgát, és pontosan mitől lesz adapter? Minden egyszerű. Az adaptálandó osztály (MemoryCard) az adapter egyik mezőjévé válik. Ennek van értelme. Ha a valóságban egy memóriakártyát teszünk a kártyaolvasóba, az is annak részévé válik. A memóriakártyával ellentétben az adapter megoszt egy interfészt a számítógéppel. USB kábellel rendelkezik, azaz USB-n keresztül csatlakoztatható más eszközökhöz. Ezért valósítja meg a CardReader osztályunk az USB interfészt. De mi történik pontosan ebben a módszerben? Pontosan annak, aminek meg kell történnie! Az adapter a memóriakártyánkra delegálja a munkát. Valójában az adapter nem csinál semmit. A kártyaolvasónak nincs önálló funkciója. Feladata csak a számítógép és a memóriakártya összekapcsolása, hogy a kártya elvégezhesse a feladatát – fájlok másolását!connectWithUsbCable()
módszer) a memóriakártya „szükségleteinek” kielégítésére. Hozzunk létre egy kliens programot, amely szimulálja azt a személyt, aki adatokat szeretne másolni a memóriakártyáról:
public class Main {
public static void main(String[] args) {
USB cardReader = new CardReader(new MemoryCard());
cardReader.connectWithUsbCable();
}
}
Szóval mit kaptunk? Konzol kimenet:
Memory card successfully inserted!
The data has been copied to the computer!
Kiváló. Célunkat elértük! Itt található egy link az adaptermintával kapcsolatos információkat tartalmazó videóhoz:
Olvasó és író absztrakt órák
Most visszatérünk kedvenc tevékenységünkhöz: néhány új kurzus megismerése a bemenettel és a kimenettel való munkavégzéshez :) Kíváncsi vagyok, mennyit tanultunk már.Reader
Ma a és az osztályokról fogunk beszélni Writer
. Miért pont ezek az osztályok? Mert ezek az adapterekről szóló előző részünkhöz kapcsolódnak. Vizsgáljuk meg őket részletesebben. Kezdjük azzal Reader
. Reader
egy absztrakt osztály, így nem tudunk explicit módon objektumokat létrehozni. De valójában már ismeri! Hiszen jól ismered a BufferedReader
és InputStreamReader
osztályokat, amelyek a leszármazottai :)
public class BufferedReader extends Reader {
…
}
public class InputStreamReader extends Reader {
…
}
Az InputStreamReader
osztály egy klasszikus adapter. Amint valószínűleg emlékszel, átadhatunk egy InputStream
objektumot a konstruktorának. Ehhez általában a System.in
következő változót használjuk:
public static void main(String[] args) {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
De mit InputStreamReader
csinál? Mint minden adapter, ez is átalakítja az egyik interfészt a másikba. Ebben az esetben az InputStream
interfész az interfészhez Reader
. Kezdetben megvan az InputStream
osztály. Jól működik, de csak egyes bájtok olvasására használható. Ezen kívül van egy Reader
absztrakt osztályunk. Van néhány nagyon hasznos funkciója – tudja, hogyan kell karaktereket olvasni! Erre a képességre mindenképpen szükségünk van. De itt szembesülünk azzal a klasszikus problémával, amelyet általában adapterek oldanak meg – az inkompatibilis interfészek. Az mit jelent? Vessünk egy pillantást az Oracle dokumentációjára. Itt vannak az InputStream
osztály metódusai. ![Adapter tervezési minta - 4](https://cdn.codegym.cc/images/article/51cb5c89-3ef3-4789-b4fd-1832bfea16ee/800.jpeg)
read()
módszer (valójában néhány változat), de csak bájtokat tud olvasni: vagy egyedi bájtokat, vagy puffer segítségével több bájtot. De ez a lehetőség nem felel meg nekünk – karaktereket szeretnénk olvasni. Szükségünk van az Reader
absztrakt osztályban már megvalósított funkciókra . Ezt láthatjuk a dokumentációban is. A és interfészek ![Adapter tervezési minta - 5](https://cdn.codegym.cc/images/article/90d6b757-f59b-4bbc-9a7e-90ebe9a0d302/800.jpeg)
InputStream
Reader
read()
InputStreamReader
Mint a fentebb vizsgált kártyaolvasó példájában, az adaptált osztály egy példányát az adapter osztályba helyezzük, azaz átadunk egyet a konstruktorának. Az előző példában egy MemoryCard
objektumot helyeztünk a belsejébe CardReader
. Most átadunk egy InputStream
tárgyat a InputStreamReader
kivitelezőnek! System.in
Ismert változónkat a következőképpen használjuk InputStream
:
public static void main(String[] args) {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
És valóban, átnézve a dokumentációt InputStreamReader
, láthatjuk, hogy az adaptáció sikerült :) Most már a karakterek olvasására szolgáló módszerek állnak rendelkezésünkre. ![Adapter tervezési minta - 6](https://cdn.codegym.cc/images/article/12ebb20e-96ec-43b9-b5cf-2fdc3ffcb0cb/800.jpeg)
System.in
objektumunk (a billentyűzethez kötött folyam) ezt kezdetben nem tette lehetővé, a nyelv készítői az adapterminta megvalósításával megoldották ezt a problémát. Az Reader
absztrakt osztálynak, mint a legtöbb I/O osztálynak, van egy ikertestvére – Writer
. Ugyanolyan nagy előnye van, mint Reader
— kényelmes felületet biztosít a karakterekkel való munkavégzéshez. A kimeneti adatfolyamoknál a probléma és annak megoldása ugyanúgy néz ki, mint a bemeneti adatfolyamoknál. Van egy OutputStream
osztály, ami csak bájtokat tud írni, van egyWriter
absztrakt osztály, amely tudja, hogyan kell dolgozni a karakterekkel, és van két nem kompatibilis felület. Ezt a problémát ismét megoldja az adapter mintája. Az osztály segítségével könnyen egymáshoz OutputStreamWriter
igazíthatjuk az Writer
és osztályok két interfészét. OutputStream
Miután átadtunk egy byte-folyamot a konstruktornak, a bájt helyett karakterek írásához OutputStream
használhatjuk a -t!OutputStreamWriter
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();
}
}
A 32144 (綐) kódú karaktert a fájlunkba írtuk, így nem kell bájtokkal dolgozni :) Mára ennyi. Találkozunk a következő leckéken! :)