Helsingin yliopisto / tietojenkäsittelytieteen laitos / Ohjelmointitekniikka (Scala) / © Arto Wikla 2016

Ohjelmointitekniikka (Scala): harjoitukset 5

Sivu julkaistu 20.4.2016

Jos käytät Scalan rakenteita, joita ei ole vielä luennoilla käsitelty, kommentoi ohjelmasi kunnolla! Varaudu myös selittämään, miten olet ohjelmoinut ja mitä ohjelmatekstisi tarkoittaa!

  1. [Laihalla implementoinnilla rikkaita rajapintoja:] Selitä Scalan tekniikka, jolla piirreluokan avulla saadaan rikkaita rajapintoja, kun sovellus toteuttaa muutaman yksinkertaisen abstraktin metodin eli vain laihan rajapinnan. Käytä esimerkkinä seuraavanlaista tapausta:
      trait KoristellenTulostettava {
        def koristettava: String
        def koristemerkki: Char
        def reunusta = println(koristemerkki + koristettava + koristemerkki)
        //... alleviivaa, ylleviivaa, ymparoi, ...
      }
    
      class Kuka(var nimi: String) extends KoristellenTulostettava {
        override def koristettava = nimi
        override val koristemerkki = '*'
      }
    
      val pm = new Kuka("Putin")
      pm.reunusta                    // *Putin*
      pm.nimi = "Obama"
      pm.reunusta                    // *Obama*
    
      class Luku(var arvo: Int) extends KoristellenTulostettava {
        override def koristettava = " " + arvo * 2 + " "
        override def koristemerkki = math.abs(arvo)%256 toChar
      }
    
      val se = new Luku(42)
      se.reunusta           // * 84 *
      se.arvo = 93
      se.reunusta           // ] 186 ]
      se.arvo = -3301
      se.reunusta           // å -6602 å
    
    Laajenna siis koristelutyylejä ainakin noilla luetelluilla: alleviivaa, ylleviivaa, ymparöi. Keksi lisää itse. Anna muitakin käyttöesimerkkejä kuin luokat Kuka ja Luku.

    Voit kehitellä myös muita esimerkkejä, jotka paremmin valaisevat tätä tekniikkaa.

  2. [Muunnoksia pinoon:] Olkoon käytössä seuraavanlaisia välineitä:
    class Opiskelija(val nimi: String,
                     var harjoitusPisteet: Int,
                     var koePisteet: Int
                    ) {
      def kokonaisPisteet = harjoitusPisteet + koePisteet
      override def toString = nimi + ": " + kokonaisPisteet
    }
    
    abstract class OpiskelijaJoukko {
      def vie(x: Opiskelija): Unit
      def poista(x: Opiskelija): Unit
    }
    
    class ToteutettuOpiskelijaJoukko extends OpiskelijaJoukko {
      import scala.collection.mutable.HashSet
    
      private val joukko = new HashSet[Opiskelija]
      def vie(x: Opiskelija) {joukko += x}
      def poista(x: Opiskelija) {joukko -= x}
      override def toString = joukko.toString
    }
    
    val masa = new Opiskelija("Matti Mainio", 7, 36)
    
    println(masa.kokonaisPisteet)  // 43
    
    val kurssi = new  ToteutettuOpiskelijaJoukko
    
    val jusa = new Opiskelija("Jussi Juonio", 2, 18)
    kurssi.vie(masa)
    kurssi vie jusa
    kurssi vie new Opiskelija("Saku Sammakko", 19, 23)
    
    println(kurssi) // Set(Saku Sammakko: 42, Matti Mainio: 43, Jussi Juonio: 20)
    
    kurssi poista jusa
    
    println(kurssi) // Set(Saku Sammakko: 42, Matti Mainio: 43)
    
    Laadi OpiskelijaJoukko-luokan alityyppeinä seuraavat piirretyypit, jotka (yhdessä tai erikseen) on tarkoitettu liitettäviksi erilaisiin OpiskelijaJoukko-luokan konkreettisten aliluokkien avulla muodostettuihin uusiin luokkiin:

    Näitä piirretyyppejä käytetään siis luentomateriaalin esimerkkien tapaan uusien luokkien muodostamiseen tyyliin

     val p = new ToteutettuOpiskelijaJoukko extends Koeleikkuri
     p vie new Opiskelija("Saku Sammakko", 19, 23)
     ...
     val v = new ToteutettuOpiskelijaJoukko with Koeleikkuri with OnnilleViisPlus
    
    Havainnollista esimerkein ja selitä, millaisia luokkia näiden piirretyyppien avulla saadaan muodostettua. Vaikuttaako piirretyyppien liittämisen järjestys muodostettavien luokkien toimintaan? Jos vaikuttaa, selitä miten vaikuttaa. Ellei vaikuta, miksi ei?

  3. [Graafista käyttöliittymää] (Kurssimateriaalin esimerkit eivät ehkä riitä näiden tehtävän tekemiseen. Varaudu siis itsenäiseen tiedonhankintaan.)

    1. Laadi yksinkertainen laskin, jossa on kentät kahdelle laskettavalle ja tulokselle sekä nappulat ainakin peruslaskutoimituksille. Näkymä voisi muistuttaa kauan sitten peruskursseilla Javalla tehtyä vastaavaa ohjelmaa:

      Kuva laskimesta

      Lay-outin suhteen kätesi ovat kuitenkin vapaat.

    2. Ohjelmoi vähintään yksi seuraavista:
      1. Toteuta tavanomainen nelilaskin.
      2. Toteuta roomalaisia numeroita käyttävä yhteen- ja vähennyslaskin. Numeronäppäimistö sisältää vähintään numeromerkit: I, V ja X. Kun kuitenkin innostut täydellisyyden tavoitteluun, ota mukaan myös merkit L, C, D ja M.
      3. Toteuta aikalaskin kolmannen kerran tehtävän 1a MinSek-arvoille. Operaatioina (so. nappuloina) tarvitaan kahden MinSek-arvon yhteen- ja vähennyslasku sekä yhden MinSek-arvon kertominen ja jakaminen kokonaisluvulla.
      4. Toteuta jokin harrastuksiisi tai kiinnostuksen kohteisiisi liittyvä edellisten kohtien henkinen ja tyylinen erikoislaskin.