Helsingin yliopisto / Tietojenkäsittelytieteen laitos / 581258-1 Johdatus ohjelmointiin
Copyright © 1998 Arto Wikla. Tämän oppimateriaalin käyttö on sallittu vain yksityishenkilöille opiskelutarkoituksissa. Materiaalin käyttö muihin tarkoituksiin, kuten kaupallisilla tai muilla kursseilla, on kielletty.

4.5 Rajapintaluokan idea

(Pikku virittelyitä 19.11.2004. Muutettu viimeksi 16.11.1998)

Jotkin erilaiset luokat voivat ominaisuuksiltaan ja käyttötavaltaan olla osittain samanlaisia. Joskus voi olla tarkoituksenmukaista käyttää toisistaan eroavien luokkien - tai niiden ilmentymien - yhteisiä ominaisuuksia ottamatta kantaa siihen, mikä erityinen luokka on kyseessä.

Yhteiset piirteet voidaan periä yhteisestä yliluokasta. Tällöin piirteet ovat täsmälleen samat. Jos ne sen sijaan ovat operaatioita, joiden käyttötarkoitus on sama, mutta toteutustapa on erilainen, metodit laaditaan kuhunkin luokkaan erikseen.

Javan rajapintaluokka (interface) on keino kerätä yhteen luokkia, joilla on joitakin samankaltaiseen tarkoitukseen laadittuja samaotsikkoisia metodeita. Rajapintaluokka pelkästään luettelee noiden yhteisten metodien otsikot - toteutustavasta ei sanota mitään.

Jatketaan kappaleen 4.1 Eläin-esimerkkiä: Kissan lisäksi Eläin-luokalla voisi olla mm. aliluokat Nauta, Hevonen, Vuohi ja Lammas, jotka täydentävät Eläin-luokalta perittyjä ominaisuuksia lajikohtaisilla ominaisuuksilla. Luokat Lehmä, Tamma, Kuttu ja Uuhi puolestaan edelleen täydentävät lajikohtaista määrittelyä kyseisten lajien naaraspuolisten yksilöiden erityisillä ominaisuuksilla.

Luokkiin Lehmä, Tamma, Kuttu ja Uuhi voidaan luontevasti määritellä mm. lypsämistoiminto. Lypsytekniikat eri luokissa toki voivat olla erilaisia.

Kaikille Eläimille yhteisiä metodeita voidaan laatia seuraavaan tapaan:

     public static void elele(Elain e, int päivienLuku) {
       for (int i=0; i<päivienLuku; ++i) {
         double painoa = e.syö(ruokaa);
         e.kasva(painoa);
         
         // ... mitä eläin sitten tekeekään ...
         // ... metodit on määritelty luokassa Elain ...
         // ... siksi niitä (ja vain niitä!) voidaan
         //     soveltaa muuttujaan e

         e.nuku();
       }
     }

Tälle metodille voitaisiin antaa parametriksi niin Kissaolio, Vuohiolio kuin vaikkapa Uuhioliokin, koska ne kaikki ovat Eläimen ilmentymiä ja siksi ovat perintönä saaneet tarvittavat operaatiot yliluokasta Eläin.

Sitä vastoin lypsämisoperaatiota kaikille Eläimille ei ole määritelty. Sellainen löytyy vain luokista Lehmä, Tamma, Kuttu ja Uuhi.

Jos haluttaisiin laatia metodi, joka lypsää parametrioliotaan, edelläoleva tapa ei onnistuisikaan: Näillä luokilla ei ole edellisen esimerkin tapaan sellaista yliluokkaa, josta löytyisi yhteinen lypsämisoperaatio! Eri lajeja lypsetään eri tekniikalla.

Apu löytyy, kun määritellään noille lypsäville yhteinen rajapintaluokka Lypsävä:

   public interface Lypsava {
     public double lypsä(); // ei algoritmia, vain otsikko!
   } 
Luokkien sanotaan toteuttavan (implement) rajapintaluokan Lypsava. Ei haittaa vaikka operaatioiden toteutuksessa on lajikohtaisia eroja, oleellista on, että kaikki lypsämismetodit tuottavat maitoa!
    public class Lehmä extends Nauta
                       implements Lypsava {
      ...
    }
Luokan alussa oleva implements-ilmaus on lupaus: luokassa on määritelty eli toteutettu kaikki kyseisen rajapintaluokan luettelemat metodit!

Rajapintaluokkaa Lypsava voidaan nyt käyttää mm. metodin parametrin tyyppinä ja näin voidaan laatia metodi, joka voi saada parametrina minkä tahansa lypsävän:

     public static double teeJuustoa(Lypsava muu) {
       double maitomäärä = muu.lypsä();
        ...
       return ...
     }

Metodi teeJuustoa voi saada parametrinaan Lehmäolion, Tammaolion, Kuttuolion tai Uuhiolion, koska kaikkien niiden luokat toteuttavat rajapintaluokan Lypsava. Sitä vastoin esimerkiksi kissanjuustoa ei ole mahdollista tehdä, koska Kissa ei toteuta Lypsava-rajapintaluokkaa.


Yllä jo esiteltiin yksi tapa toteuttaa abstrakti tietotyyppi olio-ohjelmoinnin välinein. Rajapintaluokka tarjoaa toisen tavan: Abstraktin tietotyypin voidaan ajatella olevan juuri jokin rajapintaluokka. Se ei ota kantaa - ei edes tiedä - mitkä luokat sen milloinkin toteuttavat.

Tällä tavoin ajatellen rajapintaluokka voidaan nähdä jo aiemminkin mainittuna sopimuksena abstraktin tietotyypin käyttäjän ja toteuttajan välillä. Mutta tässä tapauksessa sopimus on kuitenkin pelkästään syntaktinen, se määrää vain metodien kutsun rakenteen, ei semantiikkaa.

Jos vaikkapa ohjelmoidaan edellisen esimerkin hengessä jokin lypsysysteemi, sitä voidaan käyttää myös joskus myöhemmin luotavan luokan ilmentymän lypsämiseen kunhan tuo luokka vain toteuttaa rajapintaluokan Lypsava!


Takaisin luvun 4 sisällysluetteloon.