Kurssin viimeisimmän version löydät täältä: O1: 2024
Luku 2.2: Olion sisällä
Tästä sivusta:
Pääkysymyksiä: Miten toteutan itse (yhden) olion Scalalla? Miten olio toimii, kun sen metodia kutsutaan?
Mitä käsitellään? Yksittäisolion ohjelmakoodi, olion muuttujat,
metodien toteuttaminen, "itseen viittaaminen" eli this
.
Mitä tehdään? Pieni ohjelmointiharjoitus lyhyen pohjustuksen jälkeen.
Suuntaa antava työläysarvio:? Reilu tunti.
Pistearvo: A50.
Oheisprojektit: Oliointro.
Johdanto
Tässä luvussa määritellään yksittäisiä olioita Scala-koodissa. Osoittautuu, että se vaatii taitoa ja tekniikkaa, jota meillä on ennestään. Olion määrittelyyn sisältyy nimittäin kahdenlaisia asioita:
- Olion toiminnot kuvataan metodeina eli olioon liitettyinä funktioina. Näiden funktioiden määritteleminen onnistuu aiemmista luvuista tuttuun tapaan.
- Olio tarvitsee tavan, jolla se pitää kirjaa tiedoistaan. Tähän sopii toinen vanhastaan tuttu tekniikka eli muuttujat.
Uutta seuraavassa on lähinnä se, miten funktioita ja muuttujia liitetään olioon.
Tavoite: työntekijäolio
Laaditaan yksittäisolio, joka kuvaa erästä yksittäistä työntekijää kuvitteellisessa kirjanpitojärjestelmässä. Katsotaan kuitenkin ensin REPL-esimerkki siitä, miten haluaisimme tämän olion toimivan.
Työntekijällä on ominaisuuksia kuten nimi ja kuukausipalkka. Olion ohjelmakoodissa on määritelty näille ominaisuuksille arvot. Arvoja voi tiedustella oliolta tässä esitettyyn tapaan:
tyontekija.nimires0: String = Matti Mikälienen tyontekija.kkpalkkares1: Double = 5000.0
Vaikutukselliselle korotaPalkkaa
-metodille annetaan parametriksi luku, jolla vanha
palkka kerrotaan. Tässä siis annetaan 10 %:n palkankorotus:
tyontekija.korotaPalkkaa(1.1)
Todennetaan, että edellinen käsky todella muutti olion tilaa:
tyontekija.kkpalkkares2: Double = 5500.0
Vaikutukseton ikaVuonna
-metodi kertoo palautusarvollaan, kuinka monta vuotta työntekijä
täyttää annettuna vuonna. Työntekijäolio tietää oman syntymävuotensa ja osaa sen
perusteella laskea ja ilmoittaa ikänsä:
tyontekija.ikaVuonna(2018)res3: Int = 53
Työntekijäoliolle on määritelty työaika desimaalilukuna. Arvo 1.0 tarkoittaa täyspäiväisyyttä (100 %:n työaika):
tyontekija.tyoaikares4: Double = 1.0
Työaikaa voi muuttaa yksinkertaisesti sijoituskäskyllä (vrt. radioesimerkki luvusta 2.1), joka lähettää oliolle viestin: "Aseta työajaksesi 0.6." Arvo 0.6 tarkoittaa osa-aikaisuutta; Matti Mikälienen asetetaan tekemään 60-prosenttista työkuukautta:
tyontekija.tyoaika = 0.6tyontekija.tyoaika: Double = 0.6
Vaikutukseton kuukausikulut
-metodi laskee ja palauttaa työntekijän kuukausittaisen
hinnan työnantajalleen. Hinta lasketaan tässä esimerkissä kuukausipalkan (nyt 5500 euroa),
työajan (nyt 60 %) ja sivukulukertoimen (parametriarvo 1.3) tulona:
tyontekija.kuukausikulut(1.3)res5: Double = 4290.0
Vaikutukseton kuvaus
-metodi palauttaa merkkijonokuvauksen eräistä työntekijäolion
keskeisistä tiedoista. Metodi on parametriton, eikä kutsussa ole sulkeita nimen kuvaus
perässä (kuten ei yllä nimeä ja kuukausipalkkaa kysyessäkään ollut). Tässä kuvaus ensin
pyydetään oliolta ja sitten tulostetaan:
println(tyontekija.kuvaus)Matti Mikälienen (s. 1965), palkka 0.6 * 5500.0 euroa
Olion ohjelmakoodi ja metodien sisäinen toiminta
Työntekijäolion toteutus: yleiskuva
Alla on työntekijäolion määrittelevä ohjelmakoodi, joka löytyy myös Oliointro-projektin
pakkauksesta o1.olioita
. Koetetaan muodostaa siitä ensin kokonaiskuva ja tutkitaan
vasta sitten metodien yksityiskohtia.
object tyontekija {
var nimi = "Matti Mikälienen"
val syntynyt = 1965
var kkpalkka = 5000.0
var tyoaika = 1.0
def ikaVuonna(vuosi: Int) = vuosi - this.syntynyt
def kuukausikulut(kulukerroin: Double) = this.kkpalkka * this.tyoaika * kulukerroin
def korotaPalkkaa(kerroin: Double) = {
this.kkpalkka = this.kkpalkka * kerroin
}
def kuvaus =
this.nimi + " (s. " + this.syntynyt + "), palkka " + this.tyoaika + " * " + this.kkpalkka + " euroa"
}
val
-muuttujan arvon
voi vain "katsoa" ilmaisulla kuten tyontekija.syntynyt
, mutta
var
-muuttujalle voi myös sijoittaa uuden arvon kuten yllä
tehtiin REPLissä työajalle.def
-sanalla alkaen. Scalassa ei
ole sääntöä, joka määräisi kirjoittamaan ensin muuttujat ja sitten
metodit, mutta tämä on melko yleinen tapa. Metodeista lisää alla.Työntekijäolion sisäinen toimintatapa
Työntekijäolion toteutus: metodien koodi selitettynä
def ikaVuonna(vuosi: Int) = vuosi - this.syntynyt
def kuukausikulut(kulukerroin: Double) = this.kkpalkka * this.tyoaika * kulukerroin
def korotaPalkkaa(kerroin: Double) = {
this.kkpalkka = this.kkpalkka * kerroin
}
def kuvaus =
this.nimi + " (s. " + this.syntynyt + "), palkka " + this.tyoaika + " * " + this.kkpalkka + " euroa"
this
tarkoittaa: "se olio, jonka metodia ollaan
suorittamassa". Tai olion näkökulmasta: "minä itse". Sanaa voi
käyttää pisteen kanssa viittaamaan olion osiin. Kuten äskeisestä
animaatiosta näkyy, käytännössä this
on parametrimuuttuja,
joka toimii kuin muutkin parametrimuuttujat. Se saa arvonsa
"metodikutsusta pisteen edestä".ikaVuonna
-metodiasi
kutsutaan, vastaa luvulla, jonka saat vähentämällä parametriksi
annetusta vuodesta oman syntynyt
-muuttujasi arvon."kuvaus
-metodi ei ota parametreja, eikä sille ole edes
määritelty parametriluetteloa.this
-sanan käytöstä tarkemmin
this
-sanaa käytetään tällä kurssilla jotakuinkin aina, kun
viitataan metodia suorittavan olion omiin piirteisiin. Sana
ei kuitenkaan usein ole teknisessä mielessä pakollinen.
Joskus this
on pakollinen, mikä käy ilmi tästä työntekijäolion
versiosta, jossa on aiempaan verrattuna erilaista vain yhden
muuttujan nimi:
object tyontekija {
var nimi = "Matti Mikälienen"
val vuosi = 1965
var kkpalkka = 5000.0
var tyoaika = 1.0
def ikaVuonna(vuosi: Int) = vuosi - this.vuosi
// jne.
vuosi
eikä
syntynyt
, kuten alkuperäisessä.ikaVuonna
-metodin parametri.this
-sanaa kirjoitettu vuosi
tarkoittaa
parametrina annettua vuotta.this
kertoo, että tässä viitataan nimenomaan olion
muuttujaan eikä parametriin. Ilman sitä tämä metodi
vähentäisi parametrimuuttujansa arvon siitä itsestään
ja palauttaisi siis aina nolla.Alkuperäisen esimerkkimme työntekijäolion metodeista this
-sanan
pisteineen olisi voinut jättää joka kohdasta poiskin, koska mikään
paikallisista muuttujista ei ollut olion muuttujien kanssa
samanniminen.
Silloinkin, kun se ei ole pakollista, this
-sanan käyttö korostaa
lukijalle sitä, missä kohdissa käytetään olion muuttujia ja
missä paikallisia. Suosittelemme kaikille kurssilaisille
this
-sanan käyttöä aina olion muuttujiin viitatessa, sillä
se selkeyttää ohjelmia.
Kyseessä on osittain makuasia. Jos haluat — ja jos tiedät mitä
teet — niin saat kyllä kurssillakin jättää ei-välttämättömät
this
-sanat pois. this
-sanojen pois jättäminen sen ollessa
sallittua on kurssimme ulkopuolella varsin yleistä.
Laadi itse olio
Laadi nyt itse olio, joka kuvaa yhtä pankkitiliä. Olion on toimittava seuraavan esimerkin mukaisesti.
Tiliolio: käyttöesimerkki
Tili määritellään pakkaukseen o1.olioita
, joten:
import o1.olioita._import o1.olioita._
Tilillä on saldo (sentteinä) ja tilinumero, jotka voi kysyä siltä:
tili.saldores6: Int = 0 tili.numerores7: String = 15903000000776FI00
Tilille voi tallentaa rahaa. Tässä kuvaamme rahasummia kokonaislukuina, jotka vastaavat eurosenttien määriä. Lisätään tilille 200 euroa ja katsotaan taas saldo:
tili.talleta(20000)tili.saldores8: Int = 20000
Negatiivisen summan tallentaminen ei muuta saldoa:
tili.talleta(-1000)tili.saldores9: Int = 20000
nosta
-metodi vähentää tililtä rahaa ja palauttaa onnistuneen vähennyksen määrän:
tili.nosta(5000)res10: Int = 5000
Alle nollan ei voi vähentää. Tässä saadaan vain 150,00 euroa ja tyhjennetään tili:
tili.nosta(50000)res11: Int = 15000 tili.saldores12: Int = 0
Tehtävänanto
Määrittele siis Scalalla olio tili
, joka toimii niin kuin yllä on kuvattu ja jolla on
seuraavat piirteet:
- Sillä on muuttumaton numero
"15903000000776FI00"
. - Sillä on saldo, joka on aluksi nolla mutta joka voi muuttua.
- Sillä on metodi
talleta
, joka lisää parametriarvon verran rahaa tilille (kunhan parametriarvo on positiivinen) eikä palauta mitään. - Sillä on metodi
nosta
, joka vähentää tililtä parametriarvon verran, jos mahdollista, tai tyhjentää tilin, jos parametriarvo on saldoa suurempi. Onnistuneesti nostettu määrä palautetaan. - (Tässä tehtävässä sinun ei ole pakko huomioida mahdollisuutta, että
nosta
-metodin parametriarvo olisi negatiivinen. Kuitenkin jos haluat, voit laatia metodin sellaiseksi, että se negatiivisella parametriarvolla se jättää saldon koskemattomaksi.)
Kirjoita koodi Oliointro-projektin tiedostoon o1/olioita.scala
sille
merkittyyn kohtaan.
Toimintaohje
Kannattaa edetä seuraavasti:
- Katso käyttöesimerkki yltä huolella. Huomaa muuttujien nimet ja
tietotyypit! Ei
tilinumero
vaannumero
ja saldon tyypiksiInt
. - Etsi
olioita.scala
-tiedostosta tiliolion määrittelyn alku ja aaltosulkeet, joiden väliin olion varsinainen määritelmä kirjoitetaan. - Kirjoita muuttujien määrittelyt ja laita niille alkuarvot. Sisennä parilla lisävälilyönnillä.
- Testaa, toimiiko, Käynnistä REPL-sessio Oliointro-projektille,
anna
import
-käsky ja kokeile lausekkeitatili.saldo
jatili.numero
. - Kirjoita
talleta
- janosta
-metodit.- Käytä apuna aiemmista luvuista tuttuja
min
- jamax
-funktioita. nosta
-metodissa tarvittavaan algoritmiin tutustuit jo luvun 1.8 tehtävässä.
- Käytä apuna aiemmista luvuista tuttuja
- Nollaa taas REPL ja testaa metodeitasi erilaisilla parametriarvoilla. (Muistutus: voit myös käyttää REPLin Relaunch Interpreter and Replay History -toimintoa.)
- Palauta, kun olet vakuuttunut oliosi toimivan spesifikaation mukaisesti.
A+ esittää tässä kohdassa tehtävän palautuslomakkeen.
Mitä vikaa?
Kun olet tehnyt tehtävän, voit miettiä seuraavaa.
Teitkö pankkitilioliollesi saldo
-nimisen var
-muuttujan? Jos
teit, niin hyvä niin. Kuitenkin saatoit jo tulla ajatelleeksi
pientä kummallisuutta. Tiliolion saldoahan olisi näemmä tarkoitus
muuttaa talleta
- ja nosta
-metodeilla, jotka tekevät halutut
tarkastukset: ei lisätä negatiivista määrää eikä sallita saldon
menevän alle nollan. Kuitenkaan mikään ei estä meitä komentamasta
oliota asettamaan saldonsa negatiiviseksi näin: tili.saldo = -100000
Tietenkään tämä ei haittaa mitään, jos tuollaista sijoitusta ei koskaan tehdä. Vääränlaisen sijoituksen tekeminen on mahdollista tulkita oliota käyttävän ohjelmoijan virheeksi. Kuitenkin monien ohjelmoijien mielestä ohjelmat tulisi laatia siten, että tällaisten virheiden riski olisi mahdollisimman pieni. Opit pian (luku 3.1), miten ei-toivotun sijoituskäskyn voi estää, mutta ihan vielä siitä ei tarvitse välittää.
On olemassa ohjelmointityylejä, joissa ei luettaisi ongelmaksi sitä, että olio tarjoaa käyttäjälleen sopimattomiakin käskyjä. Scala-ohjelmoijat tapaavat kuitenkin kuulua siihen joukkoon, joista tällaisten virheiden mahdollisuuden tulee minimoida, jotta ohjelmoijan työ tehostuu ja saadaan luotua luotettavampia ohjelmistoja.
Yhteenvetoa
- Osa Scala-ohjelman olioista on ns. yksittäisolioita eli muista olioista irrallisina määriteltyjä olioita.
- Yksittäisolion määrittely koostuu muuttujien määrittelyistä ja
metodien määrittelyistä.
- Olion tietoihin voi määritellä muuttujan ja sille arvon aivan aiempien lukujen mukaisesti.
- Samoin metodien määrittelyt ovat aivan vastaavia kuin jo tutuksi tulleiden funktioiden.
- On erittäin yleistä, että metodin toteutuksessa on tarve viitata
johonkin samaisen olion (siis metodia suorittavan olion) muuttujaan
tai toiseen metodiin. Tähän voi Scalassa käyttää
this
-sanaa. - Lukuun liittyviä termejä sanastosivulla: olio, yksittäisolio;
this
.
Päivitetty käsitekaavio:
Palaute
Huomaathan, että tämä on henkilökohtainen osio! Vaikka olisit tehnyt lukuun liittyvät tehtävät parin kanssa, täytä palautelomake itse.
Tekijät
Tämän oppimateriaalin kehitystyössä on käytetty apuna tuhansilta opiskelijoilta kerättyä palautetta. Kiitos!
Kierrokset 1–13 ja niihin liittyvät tehtävät ja viikkokoosteet on laatinut Juha Sorva.
Kierrokset 14–20 on laatinut Otto Seppälä. Ne eivät ole julki syksyllä, mutta julkaistaan ennen kuin määräajat lähestyvät.
Liitesivut (sanasto, Scala-kooste, usein kysytyt kysymykset jne.) on kirjoittanut Juha Sorva sikäli kuin sivulla ei ole toisin mainittu.
Tehtävien automaattisen arvioinnin ovat toteuttaneet Riku Autio, Jaakko Kantojärvi, Teemu Lehtinen, Timi Seppälä, Teemu Sirkiä ja Aleksi Vartiainen.
Lukujen alkuja koristavat kuvat ja muut vastaavat kuvituskuvat on piirtänyt Christina Lassheikki.
Yksityiskohtaiset animaatiot Scala-ohjelmien suorituksen vaiheista ovat suunnitelleet Juha Sorva ja Teemu Sirkiä. Niiden teknisen toteutuksen ovat tehneet Teemu Sirkiä ja Riku Autio käyttäen Teemun toteuttamia Jsvee- ja Kelmu-työkaluja.
Muut diagrammit ja materiaaliin upotetut vuorovaikutteiset esitykset on laatinut Juha Sorva.
O1Library-ohjelmakirjaston ovat kehittäneet Aleksi Lukkarinen ja Juha Sorva. Useat sen keskeisistä osista tukeutuvat Aleksin SMCL-kirjastoon.
Opetustapa, jossa käytämme O1Libraryn työkaluja (kuten Pic
) yksinkertaiseen graafiseen
ohjelmointiin on saanut vaikutteita tekijöiden Flatt, Felleisen, Findler ja Krishnamurthi
oppikirjasta How to Design Programs sekä Stephen Blochin oppikirjasta Picturing Programs.
Oppimisalusta A+ on luotu Aallon LeTech-tutkimusryhmässä pitkälti opiskelijavoimin. Pääkehittäjänä toimii tällä hetkellä Jaakko Kantojärvi, jonka lisäksi järjestelmää kehittävät useat tietotekniikan ja informaatioverkostojen opiskelijat.
Kurssin tämänhetkinen henkilökunta on kerrottu luvussa 1.1.
Joidenkin lukujen lopuissa on lukukohtaisia lisäyksiä tähän tekijäluetteloon.
object
. Sen perään kirjoitetaan ohjelmoijan valitsema nimi, jolla olioon voi viitata.