Kamusta! Ngayon ay tatalakayin natin ang isang mahalagang bagong paksa - mga pattern, o sa madaling salita - mga pattern ng disenyo . Ano ang mga pattern? Sa tingin ko alam mo ang expression na "don't reinvent the wheel." Sa programming, tulad ng sa maraming iba pang mga lugar, mayroong isang malaking bilang ng mga tipikal na sitwasyon. Para sa bawat isa sa kanila, sa proseso ng pag-unlad ng programming, nilikha ang mga handa na solusyon sa pagtatrabaho. Ito ay mga pattern ng disenyo. Sa relatibong pagsasalita, ang isang pattern ay isang partikular na halimbawa na nag-aalok ng solusyon sa isang sitwasyon tulad ng: "kung may kailangang gawin ang iyong programa, kung paano ito pinakamahusay na gawin." Mayroong maraming mga pattern, isang mahusay na aklat na "Pag-aaral ng Mga Pattern ng Disenyo" ay nakatuon sa kanila, na dapat mong basahin. Upang ilagay ito nang maikli hangga't maaari, ang isang pattern ay binubuo ng isang karaniwang problema at ang solusyon nito, na maaari nang ituring na isang uri ng pamantayan. Sa lektura ngayon ay makikilala natin ang isa sa mga pattern na ito na tinatawag na "Adapter". Ang pangalan nito ay nagsasabi, at nakatagpo ka ng mga adaptor sa totoong buhay nang higit sa isang beses. Ang isa sa mga pinaka-karaniwang adapter ay ang mga card reader, na nilagyan ng maraming mga computer at laptop. Isipin na mayroon kaming ilang uri ng memory card. Ano ang problema? Ang katotohanan ay hindi niya alam kung paano makipag-ugnayan sa isang computer. Wala silang karaniwang interface. Ang computer ay may USB connector, ngunit hindi ka maaaring magpasok ng memory card dito. Ang card ay hindi maipasok sa computer, dahil dito hindi namin mai-save ang aming mga larawan, video at iba pang data. Ang card reader ay isang adaptor na lumulutas sa problemang ito. Pagkatapos ng lahat, mayroon itong USB cable! Hindi tulad ng card mismo, ang card reader ay maaaring ipasok sa isang computer. Mayroon silang karaniwang interface sa computer - USB. Tingnan natin kung ano ang magiging hitsura nito sa isang halimbawa:
public interface USB {
void connectWithUsbCable();
}
Ito ang aming USB interface na ang tanging paraan ay ang pagpasok ng USB cable:
public class MemoryCard {
public void insert() {
System.out.println("Карта памяти успешно вставлена!");
}
public void copyData() {
System.out.println("Данные скопированы на компьютер!");
}
}
Ito ang aming klase na nagpapatupad ng memory map. Mayroon na itong 2 pamamaraan na kailangan namin, ngunit narito ang problema: hindi nito ipinapatupad ang USB interface. Ang card ay hindi maaaring ipasok sa USB slot.
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();
}
}
At narito ang aming adaptor! Ano ang ginagawa ng klaseCardReader
at bakit ito isang adaptor? Simple lang. Ang klase na iniangkop (memory map) ay nagiging isa sa mga field ng adapter. Ito ay lohikal, dahil sa totoong buhay ay nagpasok din kami ng isang card sa loob ng card reader, at ito rin ay nagiging bahagi nito. Hindi tulad ng isang memory card, ang adaptor ay may karaniwang interface sa computer. Mayroon itong USB cable, ibig sabihin maaari itong kumonekta sa iba pang mga device sa pamamagitan ng USB. Samakatuwid, sa programa, CardReader
ipinapatupad ng aming klase ang USB interface. Ngunit ano ang nangyayari sa loob ng pamamaraang ito? At doon nangyayari ang eksaktong kailangan natin! Idelegate ng adapter ang trabaho sa aming memory card. Pagkatapos ng lahat, ang adaptor mismo ay walang ginagawa; ang card reader ay walang anumang independiyenteng pag-andar. Ang trabaho nito ay i-link lamang ang computer at ang memory card upang magawa ng card ang trabaho nito at makakopya ng mga file! Pinapayagan ito ng aming adaptor na gawin ito sa pamamagitan ng pagbibigay ng sarili nitong interface (paraan connectWithUsbCable()
) para sa "mga pangangailangan" ng memory card. Gumawa tayo ng ilang uri ng programa ng kliyente na gayahin ang isang taong gustong kumopya ng data mula sa isang memory card:
public class Main {
public static void main(String[] args) {
USB cardReader = new CardReader(new MemoryCard());
cardReader.connectWithUsbCable();
}
}
Ano ang nakuha namin bilang isang resulta? Output ng console:
Карта памяти успешно вставлена!
Данные скопированы на компьютер!
Mahusay, matagumpay na natapos ang aming gawain! Narito ang ilang karagdagang link na may impormasyon tungkol sa pattern ng Adapter:
- Pattern ng Video Adapter – Mga Pattern ng Disenyo ;
- Pattern ng disenyo "Adapter" / "Adapter" ;
- Mga pattern ng disenyo sa simpleng wika .
Abstract na klase Reader and Writer
Ngayon ay babalik tayo sa ating paboritong libangan: matututo tayo ng ilang bagong klase para sa pagtatrabaho sa input at output :) Ilan na sa kanila ang natutunan na natin, siguro? Ngayon ay pag-uusapan natin ang tungkol sa mga klaseReader
at Writer
. Bakit sa kanila? Dahil ito ay mauugnay sa aming nakaraang seksyon - mga adaptor. Tingnan natin ang mga ito nang mas detalyado. Magsimula tayo sa Reader
'a. Reader
ay isang abstract na klase, kaya hindi namin malinaw na magagawa ang mga bagay nito. Pero sa totoo lang, kilala mo na siya! Pagkatapos ng lahat, ang mga klase na alam mo BufferedReader
ay InputStreamReader
mga tagapagmana nito :)
public class BufferedReader extends Reader {
…
}
public class InputStreamReader extends Reader {
…
}
Kaya, ang isang klase InputStreamReader
ay isang klasikong adaptor . Tulad ng malamang na naaalala mo, maaari naming ipasa ang isang bagay sa constructor nito InputStream
. Kadalasan, gumagamit kami ng variable para dito System.in
:
public static void main(String[] args) {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
Ano ang ginagawa nito InputStreamReader
? Tulad ng anumang adaptor, nagko-convert ito ng isang interface sa isa pa. Sa kasong ito, ang interface InputStream
'a sa interface Reader
'a. Nung una may klase kami InputStream
. Gumagana ito nang maayos, ngunit maaari lamang itong magbasa ng mga indibidwal na byte. Bilang karagdagan, mayroon kaming abstract na klase Reader
. Mayroon itong mahusay na pag-andar na talagang kailangan namin - nakakabasa ito ng mga character! Siyempre, kailangan talaga natin ang pagkakataong ito. Ngunit narito tayo ay nahaharap sa isang klasikong problema na karaniwang nalulutas ng mga adaptor - hindi pagkakatugma ng interface. Paano ito nagpapakita ng sarili? Tingnan natin nang diretso ang dokumentasyon ng Oracle. Narito ang mga pamamaraan ng klase InputStream
. Ang isang hanay ng mga pamamaraan ay isang interface. Tulad ng nakikita mo, read()
ang klase na ito ay may isang pamamaraan (kahit na sa ilang mga bersyon), ngunit maaari lamang itong magbasa ng mga byte: alinman sa mga indibidwal na byte, o ilang mga byte gamit ang isang buffer. Ang pagpipiliang ito ay hindi angkop sa amin - gusto naming basahin ang mga character. Ang pag-andar na kailangan namin ay ipinatupad na sa abstract na klaseReader
. Makikita rin ito sa dokumentasyon. Gayunpaman, ang InputStream
'a' at Reader
'a' na mga interface ay hindi magkatugma! Tulad ng nakikita mo, sa lahat ng mga pagpapatupad ng pamamaraan, read()
ang mga naipasa na mga parameter at ang mga halaga ng pagbabalik ay naiiba. At ito ay kung saan kailangan namin ito InputStreamReader
! Siya ang gaganap bilang Adapter sa pagitan ng aming mga klase. Tulad ng halimbawa sa card reader, na tiningnan namin sa itaas, ipinapasa namin ang bagay ng "inangkop" na klase "sa loob," iyon ay, sa tagabuo ng klase ng adaptor. Sa nakaraang halimbawa, ipinasa namin ang isang bagay MemoryCard
sa loob CardReader
. Ngayon ipinapasa namin ang bagay InputStream
sa tagabuo InputStreamReader
! Bilang isang kalidad InputStream
ginagamit namin ang pamilyar na variable System.in
:
public static void main(String[] args) {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
At sa katunayan: sa pamamagitan ng pagtingin sa dokumentasyon InputStreamReader
makikita natin na ang "pagbagay" ay matagumpay :) Ngayon ay mayroon na tayong mga pamamaraan sa pagtatapon na nagpapahintulot sa amin na magbasa ng mga character. At kahit na sa una System.in
ay hindi ito pinayagan ng aming object (isang thread na nakatali sa keyboard), sa pamamagitan ng paglikha ng Adapter pattern, nalutas ng mga tagalikha ng wika ang problemang ito. Ang abstract class Reader
, tulad ng karamihan sa I/O classes, ay may kambal na kapatid na lalaki - Writer
. Ito ay may parehong malaking kalamangan Reader
- nagbibigay ito ng isang maginhawang interface para sa pagtatrabaho sa mga simbolo. Sa mga output stream, ang problema at ang solusyon nito ay kapareho ng hitsura sa kaso ng mga input stream. Mayroong isang klase OutputStream
na maaari lamang magsulat ng mga byte; Mayroong isang abstract na klase Writer
na maaaring gumana sa mga simbolo, at mayroong dalawang hindi magkatugma na mga interface. Ang problemang ito ay muling matagumpay na nalutas ng Adapter pattern. Gamit ang isang klase, OutputStreamWriter
madali nating "maaangkop" ang dalawang interface ng klase Writer
sa OutputStream
isa't isa. At, na nakatanggap ng isang byte stream OutputStream
sa constructor, sa tulong na OutputStreamWriter
maaari naming, gayunpaman, magsulat ng mga character, hindi bytes!
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();
}
}
Sumulat kami ng isang character na may code 32144 - 綐 sa aming file, kaya inaalis ang pangangailangan na magtrabaho sa mga byte :) Iyon lang para sa araw na ito, magkita-kita tayo sa mga susunod na lektura! :)
GO TO FULL VERSION