Johdatus olio-ohjelmointiin

Ei ole olemassa vain yhtä oikeaa ohjelmointitapaa. Viime luvussa lähdit pilkkomaan ohjelmaasi pienempiin osiin, joita sitten kutsuit draw-metodin sisältä. Tällaista ohjelmointitapaa, jossa ohjelma jäsennellään pienemmiksi aliohjelmiksi, kutsutaan proseduraaliseksi ohjelmoinniksi. Lähdemme nyt toteuttamaan hieman monimutkaisempaa toiminnallisuutta olio-ohjelmoinnin avulla. Aihe on laaja, joten kurssimateriaali on vain pintaraapaisu olioiden käyttöön.

Olio-ohjelmoinnissa ohjelman rakenne muodostuu olioista, joilla on kullakin oma roolinsa ja vastuunsa ohjelman toiminnassa. Olioon voi varastoida tietoa ja se voi toteuttaa erilaisia metodeja kutsuttaessa. Esimerkiksi Pelaaja-oliossa voisi olla tieto pelaajan sijainnista x- ja y-koordinaatteina, liiku-metodi, joka muttaa näitä koordinaatteja, sekä piirra-metodi, joka piirtää pelaajan hahmon koordinaattien osoittamaan paikkaan.


Luokat ja oliot

Aiemmin olemme käsitelleet muuttujia ja niiden tyyppejä. Esimerkiksi muuttujan 'x' tyyppi on kokonaisluku eli int jos se on määritelty seuraavalla tavalla: int x = 0; Tai esimerkiksi muuttujan 'nimi' tyyppi on merkkijono eli String jos se on määritelty seuraavasti: String nimi = 'Saara'. Vastaavalla tavalla olion tyyppi on sen luokka.

Ajatellaan esimerkiksi luokkaa 'Pankkitili'. Pankkitilillä on jokin saldo, pankkitililtä voi nostaa ja pankkitilille voi tallettaa rahaa. Seuraava koodinpätkä luo Pankkitili-luokasta uuden olion ja tallentaa sen 'tili' -nimiseen muuttujaan:

Pankkitili tili = new Pankkitili();

Oliot ovat siis luokkien konkreettisia ilmentymiä. Luokat määrittelevät, millaisia oliot ovat ja miten ne toimivat. Ennen kuin johonkin luokkaan kuuluva olio on luotu new-komennolla, luokan metodeihin ei pääse käsiksi. Luokka on vähän kuin olion pohjapiirros: emme voi vierailla talossa, jos siitä on olemassa vain piirustukset.

Piirustukset kuitenkin tarvitaan, jotta voimme rakentaa talon. Määritellään siis ensin hyvin yksinkertainen Pelaaja-luokka. Aloitetaan lisäämällä ohjelmaamme uusi välilehti. Näin useiden olioiden hallitsemisesta tulee helpompaa:

Klikkaa merkittyä kohtaa, valitse new tab ja anna uudelle välilehdelle nimeksi vaikkapa Pelaaja. Määritellään nyt yksinkertainen Pelaaja-luokka seuraavasti uuteen välilehteen:

class Pelaaja {   // Pelaaja-luokan määrittely on aaltosulkeiden sisällä
// jokaisella Pelaaja-luokan oliolla on tiedossa omat x- ja y-koordinaattinsa
  float x;   
  float y;   

// tämä on konstruktori: sen sisältö suoritetaan aina kun 
// luodaan uusi Pelaaja-luokan olio
  Pelaaja(){       
    this.x = 50;   // asetetaan uudelle oliolle sijainti
    this.y = 50;   // this.x ja this.y viittaavat olion sisäisiin muuttujiin
  }
}

Nyt olemme määritelleet Pelaaja-luokan. Luodaan seuraavaksi uusi pelaaja-olio. Uusi olio luodaan new-komennolla ensimmäisellä välilehdellä:

Pelaaja pelaaja;

void setup(){
  size(500, 500);
  pelaaja = new Pelaaja(); // luodaan uusi Pelaaja-luokan olio nimeltä pelaaja
}

void draw(){

}

Komento new kutsuu siis luokan konstruktoria, joka asettaa oliolle x- ja y-koordinaatit. Nyt meillä on pelaaja-muuttujassa olio, joka sijaitsee ruudulla kohdassa 50, 50. Nyt oliota voi käsitellä ihan kuin mitä tahansa muuttujaa, sen voi esimerkiksi antaa parametrina metodille.

Ohjelmointitehtävä

Kirjoita koodinpätkä, jossa luot Adventurer-luokasta uuden olion, tallennat olion muuttujaan ja kutsut luokan metodia "recover".

Tässä Adventurer-luokka testaamista varten:

class Adventurer {
  int health;   
  Adventurer() {
    this.health = 10;
  }
  void recover() {
    this.health += 1;
  }
}

Ohjelmointitehtävä 2

Tässä tehtävässä Adventurer-luokan konstruktori ottaa parametrinä pelaajan nimen.

Luo Adventurer-luokasta olio ja kutsu sen jälkeen luokan metodia “info”.

Tässä Adventurer-luokka testaamista varten:

class Adventurer {
  String name;
  Adventurer(String givenName) {       
    this.name = givenName;
  }
  void info() {
    print("Name: " + name);
  }
}

Luokan metodit

Pelaaja-oliomme ei vielä tee mitään. Lisätään Pelaaja-luokalle pari metodia, jotta saamme ohjelmaamme vähän toimintaa. Luokan metodit toimivat muuten kuten tavanomaiset omat metodit, paitsi että olioon liittyvää metodia kutsutaan aina kyseisen olion kautta.

Luodaan uudet metodit Pelaaja-luokalle: piirra ja liiku. Piirra-metodi piirtää haluamamme kuvion kutsuttaessa, ja liiku-metodi muuttaa pelaaja-olion sijaintia.

// Pelaaja-luokan määrittely on aaltosulkeiden sisällä
class Pelaaja {   

// jokaisella Pelaaja-luokan oliolla on tiedossa omat x- ja y-koordinaattinsa
  float x;   
  float y;   

  Pelaaja(){        // tämä on konstruktori: sen sisältö suoritetaan aina 
                    // kun luodaan uusi Pelaaja-luokan olio
    this.x = 50;    // asetetaan uudelle oliolle sijainti
    this.y = 50;    // this.x ja this.y viittaavat olion sisäisiin muuttujiin
  }

// määritellään piirra-metodin sisälle, miltä haluamme pelaajahahmomme näyttävän
  void piirra(){  
    fill(255, 255, 0);
    arc(this.x, this.y, 50, 50, QUARTER_PI, TWO_PI-QUARTER_PI, PIE);
    fill(0);
    ellipse(this.x, this.y-10, 5, 5);
  }

// liiku-metodi saa parametrina kaksi kokonaislukua
  void liiku(int suunta_x, int suunta_y){   
    this.x += suunta_x;    // lisätään nämä parametrit pelaajaolion koordinaatteihin
    this.y += suunta_y;    // tarkoittaa samaa kuin this.y = this.y + suunta_y;
  }
}

Nyt voimme kutsua olion metodeja. Koska kyseessä on olion metodi, emme kirjoita piirra(); vaan pelaaja.piirra();

Pelaaja pelaaja;

void setup(){
  size(500, 500);
// luodaan uusi Pelaaja-luokan olio nimeltä pelaaja
  pelaaja = new Pelaaja(); 
}

void draw(){
  background(255);
  pelaaja.piirra();  // kutsutaan pelaaja-olion metodia piirra()
}

void keyPressed(){   
  // keyPressed-metodia kutsutaan, kun jotakin näppäimistön 
  // näppäintä on painettu, joten tutkitaan, onko näppäin 
  // jokin nuolinäppäimistä. voit käyttää else if-rakennetta
  // tai kirjoittaa kaikki neljä erillisiksi if-lauseiksi. 
  // kutsutaan sitten liiku-metodia sopivilla paramtereilla.

  if (keyCode == RIGHT){ 
    pelaaja.liiku(10, 0);
  } else if (keyCode == LEFT){
    pelaaja.liiku(-10, 0);
  } else if (keyCode == UP){
    pelaaja.liiku(0, -10);
  } else if (keyCode == DOWN){
    pelaaja.liiku(0, 10);
  }
}

Kokeile suorittaa ylläoleva ohjelma. Sait nyt jonkinlaisen käsityksen olio-ohjelmoinnista. Mikäli haluat tutustua aiheeseen tarkemmin, kannattaa tutkia Processing.orgin Object-tutoriaalia.