5. praktikum. Harjutused.
NB! Praktikumiülesandeid antakse alati varuga, et ka kõige kiirematel/kogenumatel lahendajatel jätkuks tegevust. Seega pole mõtet kurvastada, kui te ei jõua kõiki lahendada.
1. Lõbustuspargi simulaator
Selles ülesandes loome mitu lõbustuspargiteemalist klassi, millega saab uurida lõbustuspargi külastusi, piletitulu ja vanuspiirangute mõju. Selle tarvis tekitame külastaja klassi, mille isend oskab erinevaid lõbustusi külastada ja toimunud sündmused salvestada.
1.1. Looge aluskood
Selles ülesandes tuletame meelde isendiväljad, konstruktorid ja meetodid. Hilisemad ülesanded muudavad ja täiendavad kirjutatud aluskoodi.
- Looge klass
Külastaja
.- Lisage privaatne isendiväli
külastuseKirjeldused
, mis onList<String>
tüüpi. AlgväärtustagekülastuseKirjeldused
konstruktoris - looge seal selleks tarbeks uusArrayList<String>
isend. - Lisage
void
meetodlisaKirjeldus
, mis võtab parameetriks sõne. Meetod lisab parameetriks antud sõnekülastuseKirjeldused
listi. - Lisage meetod
kõikKirjeldused
, mis tagastabkülastuseKirjeldused
.
- Lisage privaatne isendiväli
- Looge klass
Vaateratas
.- Lisage
void
meetodlõbusta
, mis võtab parameetriksKülastaja
isendi. Meetod lisab külastajale kirjelduse "külastasin vaateratast".
- Lisage
- Looge klass
Lõbustuspark
.- Lisage privaatne isendiväli
lõbustus
, mis onVaateratas
tüüpi. Lisage konstruktor, mille parameetri kaudu saab lõbustuse väärtustada. - Lisage
void
meetodalustaSeiklust
, mis võtab parameetriksKülastaja
isendi. Meetod väljastab ekraanile "alustan seiklust", kutsub välja lõbustuselõbusta
meetodi ja siis väljastab külastaja kõik kirjeldused.
- Lisage privaatne isendiväli
- Looge klass
Test
, kus on ainult peameetod. Peameetodis tee järgnevat:- Looge isend
Vaaterattast
; - Looge isend
Lõbustuspargist
, kasutades olemasolevat vaateratast; - Looge isend
Külastajast
; - Pange külastaja lõbustusparki seiklema.
- Looge isend
1.2. Kasutage liidest
Selles ülesandes tuletame meelde liidese kõige lihtsama kasutusjuhu. Loome uue lõbustuse ja muudame lõbustusparki, nii et seal saab ainult vaateratta asemel kõiki sobilikke lõbustusi kasutada.
- Looge klass
Lasketiir
.- Lisage
void
meetodlõbusta
, mis võtab parameetriksKülastaja
isendi. KasutageMath.random
ja genereerige täisarv vahemikus 0-20. Meetod lisab külastajale kirjelduse "tabasin lasketiirus N sihtmärki", kus N on genereeritud arv.
- Lisage
- Looge liides
Lõbustus
. Liides kirjeldabvoid
meetoditlõbusta
, mis võtab parameetriksKülastaja
isendi. - Muutke
Vaateratast
jaLasketiiru
, nii et nad realiseerivad liidestLõbustus
. - Muutke
Lõbustusparki
:- Muutke isendiväli
lõbustus
tüüp listiks, mis hoiabLõbustusi
. Nimetage isendiväli ümber:lõbustused
. - Muutke konstruktorit nii, et antakse ette
List<Lõbustus>
, mitte üksik lõbustus. - Muutke
alustaSeiklust
meetodit, nii et külastaja läbib järjest kõik lõbustused.
- Muutke isendiväli
- Muutke
Test
peameetodit:- Looge isend
Lasketiirust
; - Lõbustuspargi loomisel andke argumendiks list, milles on vaateratas ja lasketiir.
- Looge isend
1.3. Kohandage kangekaelset klassi
Meil on tihti vaja kasutada klasse, mida me ise muuta ei saa (nt Java sisse-ehitatud tüübid ja kood, mis on kirjutatud teiste ettevõtete poolt). Mõnikord on vaja panna mõni selline klass realiseerima mingit enda liidest. Sellisel juhul saab tekitada uue klassi, mis "mähib" olemasoleva klassi isendi ja kohandab ta vajaliku liidese realisatsiooniks, delegeerides põhitöö olemasolevale klassile. Seda tehnikat kutsutakse adapter pattern.
- Lisage enda koodi järgnev klass. Seda klassi ei tohi muuta (sh ei tohi lisada liideseid ega meetodeid).
public class Kloun { private String nimi; public Kloun(String nimi) { this.nimi = nimi; } public void esine(Külastaja külastaja) { külastaja.lisaKirjeldus("nägin klouni nimega " + nimi); } }
- Looge klass
LõbustavKloun
, mis realiseerib liidestLõbustus
.- Lisage privaatne
Kloun
tüüpi isendivälikloun
ja loo konstruktor, mille parameetri kaudu saab selle väärtustada. - Realiseerige meetod
lõbusta
. Meetod kutsub klouni esinemise meetodit.
- Lisage privaatne
- Muutke
Test
peameetodit. LoogeKlouni
isend (argumendiks andke enda lemmik klouninimi). KasutageLõbustavKloun
klassi, et lisada kloun lõbustuspargi lõbustuste listi.
1.4. Muuda funktsionaalsust ilma klassi muutmata
Mõnikord on vaja lisada klassidele funktsionaalsust. Kui sama funktsionaalsus on vaja lisada mitmele klassile, siis ei ole praktiline koodi mitmesse klassi kopeerida-kleepida. Kui klassid realiseerivad sama liidest, saab neile hoopis liidestega trikitades koodi juurde "kleepida". Selle kohta öeldakse decorator pattern.
Selleks tuleb luua uus klass, mis realiseerib soovitud liidest, aga mis delegeerib kõik meetodid teisele sama liidest realiseeriva klassi isendile. Enne ja/või pärast delegeerimist saab decorator teha täiendavaid tegevusi.
- Muutke
Külastaja
klassi. Lisage privaatneint
tüüpi isendivälivanus
. Lisage vastavget
-meetod. Lisage konstruktor, mille parameetri kaudu saab vanuse väärtustada. - Looge klass
VanuseKontrollija
, mis realiseerib liidestLõbustus
.- Lisage konstruktor, mis võtab kaks parameetrit:
nõutudVanus
(tüüpiint
) jadelegaat
(tüüpiLõbustus
). Lisage vastavad privaatsed isendiväljad ja väärtustage need konstruktoris. - Realiseerige meetod
lõbusta
. Meetodis kutsuge välja delegaadilõbusta
meetod (delegeeri ilma funktsionaalsust muutmata). - Täiendage
lõbusta
meetodit. Meetod peab kontrollima külastaja vanust. Kui külastaja vanus on nõutud vanusest väiksem, siis tuleb lisada külastajale kirjeldus "külastaja ei läbinud vanusekontrolli" ja delegaati mitte kasutada. Kui vanus on sobilik, siis tuleb kutsuda delegaadilõbusta
meetod.
- Lisage konstruktor, mis võtab kaks parameetrit:
- Muutke
Test
peameetodit.- Tekitage
VanuseKontrollija
isend, kus nõutav vanus on 10 ja delegaat on lasketiiru isend. Pange lõbustuspargi argumendiks antavasse listi lasketiiru asemel hoopis vanusekontrollija, mis delegeerib lasketiirule. - Tehke algse külastaja asemel kaks külastajat, üks vanusega 9 ja teine vanusega 11. Seigelge mõlemaga lõbustuspargis. Ainult 11-aastane külastaja peaks lasketiiru jõudma.
- Tekitage
1.5. Delegaatide ahelad
Eelmises ülesandes loodud VanuseKontrollijat
saab lisaks lasketiirule ka vaateratta ja klouniga kasutada, sest VanuseKontrollija
oskab delegeerida ükskõik millisele Lõbustusele
. Tegelikult ei pea ta üldse lõbustusele delegeerima - delegeerida võib ka mõnele teisele delegeerijale, lõbustus võib tulla alles pärast pikka delegeerimiste ahelat.
Selles ülesandes kasutame taaskord decorator patternit ja loome TasulineLõbustus
klassi. Seejärel ehitame delegeerimiste ahela - külastaja läbib kõigepealt vanusekontrolli, siis külastab lõbustust ja alles lõpus maksab piletiraha.
- Muutke
Külastaja
klassi. Lisage privaatnedouble
tüüpi isendivälikulud
. Lisagevoid
meetodlisaKulu
, mis võtab parameetriksdouble
tüüpi kulu ja suurendab selle võrra kulude isendivälja. Lisage meetodkuludeSumma
, mis tagastab kulude isendivälja väärtuse. - Muutke
Lõbustuspark
klassi, nii et pärast kõigi lõbustuste külastamist väljastatakse ka lõbutsemisel tehtud kulutuste summa. - Looge klass
TasulineLõbustus
, mis realiseerib liidestLõbustus
.- Lisage konstruktor, mis võtab kaks parameetrit: hind (tüüpi
double
) ja delegaat (tüüpiLõbustus
). Lisage vastavad privaatsed isendiväljad ja väärtustage need konstruktoris. - Realiseerige meetod
lõbusta
. Meetod kutsub delegaadilõbusta
meetodi ja pärast selle lõpetamist lisab külastajale ettemääratud kulu ja kirjelduse "tasusin külastuse eest " + hind.
- Lisage konstruktor, mis võtab kaks parameetrit: hind (tüüpi
- Muutke
Test
peameetodit.- Tekitage
TasulineLõbustus
isend, kus hind on 2.25 ja delegaat on vaateratta isend. Kasutage lõbustuspargi argumendiks antavas listis vaateratta asemel tasulist vaateratast. - Tekitage
TasulineLõbustus
isend, kus hind on 1.5 ja delegaat on lasketiiru isend. AndkeVanuseKontrollija
argumendiks lasketiiru asemel tasuline lasketiir (vanusekontrollija delegeerib tasulisele külastusele, mis delegeerib lasketiirule). - Kirjeldage kommentaaris, mis juhtuks, kui hoopis
TasulineLõbustus
delegeeriks vanusekontrolliga lasketiirule (objektid on üksteise sees teises järjekorras). Kuidas koodi käitumine muutuks?
- Tekitage
2. Failipuu läbimine
Javas on sisseehitatud meetod Files.walkFileTree
, mis läbib rekursiivselt etteantud failisüsteemi kausta ja kõik selles sisalduvad failid. Iga leitud kausta ja faili kohta antakse meetodi argumendiks antud vaatleja-objektile teada.
Seotud javadoc:
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/nio/file/FileVisitor.html
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/nio/file/Path.html
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/nio/file/Files.html
Kui kompilaator hakkab exceptionite teemal virisema ("unhandled exception .."), siis lisage selle meetodi päisesse deklaratsioon throws Exception
. (Kui teie IDE soovitab selle asemel try-catch plokke kasutada, siis ära teda kuula.)
public static void main(String[] args) throws Exception { }
2.1. Failide väljastamine
Selles ülesandes kasutame Files.walkFileTree
meetodit, et väljastada ekraanile kõik etteantud kaustas olevad failid.
- Looge klass
FailiVaatleja
, mis realiseerib liideseFileVisitor<Path>
.- Kõigi
FileVisitor
liidese meetodite tagastustüüp onFileVisitResult
. Meie programmis on sobilik tagastada kõigis liidese meetoditesFileVisitResult.CONTINUE
. - Väljastage
visitFile
meetodis parameetriga ette antud failinimi ekraanile.
- Kõigi
- Looge klass
FailiTest
, kus on peameetod.- Kasutage käsureal sisestatud kaustanime. Loo sellest
Path
objekt, kasutadesPath.of
meetodit. Käsurea parameetritest oli juttu ka 2. praktikumis. (Kui sul on vana Java versioon, siis kasutaPath.of
asemelPaths.get
.) - Kontrollige, et loodud tee on kaust, kasutades
Files.isDirectory
meetodit. Kui käsureal sisestatud asukoht ei viita kaustale, siis väljasta veateade ja lõpeta programmi töö (return
peameetodist). - Looge
FailiVaatleja
isend. - Kutsuge
Files.walkFileTree
meetod. Andke argumentideks loodud tee ja failivaatleja. Käivitage programm ja veenduge, et failivaatleja väljastab etteantud kausta sisu, selles olevate kaustade sisud jne.
- Kasutage käsureal sisestatud kaustanime. Loo sellest
2.2. Failide sorteerimine
Selles ülesandes täiendame oma failinimede väljastajat, nii et nimed väljastatakse sorteeritud järjekorras. Sorteerimise järjekorra määramiseks kasutame Comparator<T>
liidest.
Comparator
liidese javadoc: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Comparator.html
- Muutke
FailiVaatleja
klassi. Lisage privaatneList<String>
tüüpi isendivälifailiNimed
. Väärtustage see konstruktoris uueArrayList<String>
isendiga. Lisage vastavget
-meetod. - Muutke
visitFile
meetodit, nii et iga külastatud fail lisataksefailiNimed
listi.Path
objekti võib sõneks teisendada, kasutadestoString
meetodit. Ärge siin meetodis midagi ekraanile väljastage. - Muutke
FailiTest
peameetodit. PärastwalkFileTree
meetodi lõppu sorteeri failivaatlejasse kogunenud failide nimed ja väljastage need ekraanile. Sorteerimiseks kasutageCollections.sort
meetodit. Veenduge, et nimed on tähestikujärjekorras. - Lisage klass
NimeVõrdleja
, mis realiseerib liidestComparator<String>
(toimib väga sarnaseltComparable
liidesega). Realiseerigecompare
meetod nii, et sõned sorteeritakse tavalisest vastupidises järjekorras (["a", "b", "c"]
vs["c", "b", "a"]
). Vihje:Comparator
realiseerimiseks peab looma ainultcompare
meetodi (ära default meetodeid üle kirjuta). - Muutke peameetodis
Collections.sort
väljakutset, nii et sorteerimisalgoritm kasutaks teie loodudNimeVõrdlejat
(Collections.sort(List<T>, Comparator<T>)
). Veenduge, et nüüd sorteeritakse failide nimed tähed-enne-numbreid.