Oon juuri aloittanut java ohjelmoinnnin ja hankalaksi itselle on osoittunut olio-ohjelmointi. Tein yksin kertaisen nopan jossa käytän olioita. Voisiko joku osaava katsoa mikä minulla on pielessä kun koodi tulostaa vastaukseen kummia tekstejä. Toivoisin ettö joku myös katsoisi että oliko tämä hyvä tapa kirjoittaa noppa koodi vai olisiko joku muu parempi.
package olioNoppa; public class luokka { public static void main(String[] args) { arpoja heitto = new arpoja(3); System.out.println(heitto); } }
package olioNoppa; import java.util.Random; public class arpoja { Random ran = new Random(); private int noppa; public arpoja(int kerrat){ heitot(kerrat); } public void heitot(int kerrat){ while(kerrat>0){ this.noppa = 1+ran.nextInt(6); kerrat--; System.out.println(noppa); } } }
Tulostaa
5
4
4
olioNoppa.arpoja@6d06d69c
Mun mielestä tossa nyt on suunnilleen kaikki pielessä. Tosin voihan olla vähän makuasiastakin kyse.
- Miksi arpoja-luokalle annetaan alustuksessa montako kertaa sitä heitetään?
- Miksi arpojaluokka tulostaa suoraan System.Outiin?
- Miksi noppa muuttuja on luokassa vaikka sitä ei käytetä kuin heitot-funktiossa (eikä funktion sisäisenä)?
- Miksi tulostat lopuksi olion System.out.println:iin?
Sinänsä tuloste näyttää juuri siltä mitä olet käskenytkin tehdä.
Toimiiko noppa mielestäsi oikeasti niin, että kun noppatehtaassa valmistetaan noppa, se pyörähtää kolmesti ja hihkaisee silmälukunsa eikä sitten enää tee mitään? Ei tietenkään!
Nyt olet päättänyt valmiiksi, mitä ohjelman pitää tehdä, ja olet tunkenut sen idean jollain mielivaltaisella tavalla luokkien sisään. Tämä ei vastaa olio-ohjelmoinnin ideaa.
Nopan luomiseen on loogista antaa vaikkapa sivujen määrä (ellei tarkoitus ole ohjelmoida juuri 6-sivuista noppaa), ja nopan keskeinen ominaisuus on yksi heitto, joka tuottaa yhden luvun. Heittojen määrä ja tulosten ilmoittaminen kuuluvat muualle, vaikkapa main-metodiin.
Toisaaltahan toi luokka on nimeltään arpoja. Sitä voisi ehkä ajatella ikäänkuin lottokoneena.. Siinähän on palloja ja se arpoo niitä 8 kpl (muistaakseni). Eli ehkä toi arpoja -olio on olevinaan ikäänkuin noppakone joka arvoo määrätyn määrän numeroita heittämällä noppaa.
Kritiikkini pääkohdat onneksi pätevät, vaikka tavoitteena olisi arpoja.
Tein ajankuluksi yhden esimerkin. Vähän haastavaa keksiä mitään hienoa olioesimerkkiä näin yksinkertaisesta toiminnallisuudesta, mutta jokatapauksessa: IDEOne
Tuo lopun outo teksti johtuu siitä, että tulostat mainin lopussa itse heitto-olion, jolloin Java sylkee ulos sen toString metodin palautuksen. En tiedä miksi se siinä on, mutta jos haluat jotain tiettyä ulos siinä kohtaa, kannattaa oliolle luoda kustomi toString-metodi.
Olio-ohjelmoinnista yleisesti; luokkien olisi hyvä edustaa yhtä asiaa. Sinulla on nyt arpoja luokka, joka edustaa monta arpaa kerralla. Tee mieluummin yksi arpa-luokka ja luo siitä useampi arpa-olio.
Esimerkiksi:
import java.util.Random; Public class Noppa { private int sivuja; private Random random; public Noppa(int sivuja) { // Annetaan konstruktorille sivujen määrä, jos vaikka // tarvitaan 20-sivuisia noppia. this.sivuja = sivuja; this.random = new Random(); } public int heitto() { return this.random.nextInt(sivuja) + 1; } }
Yllä olevasta luokasta voidaan sitten luoda olioita vaikka mainissa tai toisessa oliossa:
import java.util.ArrayList; import java.util.List; public class Heitot { public static void main(String[] args) { // Tässä vain luodaan ArrayList johon voi varastoida noppa-olioita List<Noppa> noppaVarasto = new ArrayList<>(); // Luodaan nopat for (int index = 0; index < 4; index++) { noppaVarasto.add(new Noppa(6)); } // Heitetään ja tulostetaan nopat for (Noppa noppa : noppaVarasto) { System.out.println(noppa.heitto()); } } }
Tuossa turhaan luodaan monta noppaa, mutta kirjoitan tabletilla enkä jaksa korjata. Toivottavasti selventää asiaa.
Edit: Pääsin näppäimistön ääreen, joten kokeillaan uudelleen.
Voit käyttää Noppa-luokkaa esim. seuraavasti:
public class Heitot { public static void main(String[] args) { Noppa kuusiSivuinenNoppa = new Noppa(6); Noppa kymmenenSivuinenNoppa = new Noppa(10); System.out.println(kuusiSivuinenNoppa.heitto()); System.out.println(kymmenenSivuinenNoppa.heitto()); } }
Jos Noppa-metodia haluaisi jalostaa lähemmäksi sinun alkuperäistä ajatusta, sen voisi overloadata, jolloin on mahdollista antaa heitto-metodille vapaaehtoinen luku (noppa.heitto(3)), jonka perusteella heitetään tietty määrä heittoja. Noppa.heitto() silti antaisi vain yhden heiton. Mutta en tiedä kuinka pitkälle olet päässyt opiskelussa ja tuo saattaa sekoittaa vain entisestään...
Kiitos todella paljon vastauksista. Erityis kiitos Jtontulle. Neuvoit todella hyvin asian. Olen oppinut tämän kyllä mutta sen toteutus on todella hankalaa. Menen heti kokeilemaan noita parannuksia.
Lisäys:
package olioNoppa; public class luokka { public static void main(String[] args) { arpoja noppa = new arpoja(6); int tulos = noppa.heitto(); System.out.println(tulos); } }
package olioNoppa; import java.util.Random; public class arpoja { private Random ran; private int sivut; private int tulos; public arpoja(int sivut){ this.sivut = sivut; ran = new Random(); } public int heitto(){ tulos = this.ran.nextInt(1+sivut); return tulos; } }
Siinä se nyt on. Sanokaa jos siinä on vielläkin jotain pielessä. :D
E1ss kirjoitti:
public class arpoja { [..] private int tulos; [..] public int heitto(){ tulos = this.ran.nextInt(1+sivut); return tulos; } }
Luokat on yleensä tapana nimetä isolla alkukirjaimella, eli Arpoja
olisi parempi.
Muuttujat kannattaa määritellä pienimmässä tilassa, jossa niitä käytetään. Se helpottaa koodin ymmärtämistä. Koska tulosta tarvitaan vaan heitto()
-metodin sisällä, sen voi määritellä siellä.
public int heitto() { int tulos = this.ran.nextInt(1+sivut); return tulos; } public int heitto2() { // Koko muuttuja on itse asiassa turha: return this.ran.nextInt(1 + this.sivut); }
Viittaat jäsenmuuttujiin välillä this:n
kautta (this.ran
) ja välillä ilman (sivut
). Kannattaa valita jompi kumpi käytäntö ja pitäytyä siihen.
Kiitos tästä palautteesta. Tein muutokset koodiin ja uskon se hipovan nyt täydellisyyden rajaa.
nextInt(n)
palauttaa luvun välillä 0–(n-1), joten nyt koodi palauttaa lukuja liian suurelta väliltä (esim. randInt(1+6)
palauttaa jonkun luvun 0, 1, 2, 3, 4, 5, 6; eli 0-6). Jos haluat luvun väliltä 1-6, oikea koodi olisi randInt(6)+1
.
Hyvä huomio. En pääse nyt titokoneelle kokeilemaan tätä mutta näyttäisi loogiselta. Sanokaa muutkin "ammattilaiset" meneekö se todella näin.
No mutta mikset itse katso dokumentaatiosta? Kyllähän sen saa luettua kännykälläkin.
https://docs.oracle.com/javase/8/docs/api/java/
nextInt(int bound)
Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive), drawn from this random number generator's sequence.
En usko että "ammattilaisia" sinänsä kiinnostaa alkaa asiaa pohtimaan, ellei joku väitä että se toimisi dokumentaation vastaisesti.
Aihe on jo aika vanha, joten et voi enää vastata siihen.