Yleisesti olio-ohjelmoinnista
ALIGN="CENTER">Olio-ohjelmistojen uudelleenkäytöstä
Olioparadigma tukee uudelleenkäytön ajatusta (esim. periytyminen), mutta muutakin tarvitaan.
White-box reuse eli muuntava uudelleenkäyttö tarkoittaa sitä, että aliluokka voidaan toteutaa yliluokkansa avulla. Tällöin uudelleenkäytettävä koodi on näkyvissä ja sitä voidaan muunnella aliluokassa asianomaisen operaation kohdalla.
Kompositio tarkoittaa sitä, että olioita kotaan yhteen uutta kokonaisuuta varten. Kompositio suoritetaan viiteatribuuttien (joskus myös alistettujen olioiden) avulla.
Black-box reuse eli kokoava uudelleenkäyttö tarkoittaa puolestaan kompositioon perustuvaa uudelleenkäyttöä. Koodi ei tuolloin ole näkyvissä vaan uudelleenkäyttö perustuu rajapintoihin. Voidaan sanoa tiivistetysti, että kokoava uudelleenkäyttö on "modulaarisempaa" kuin muuntava uudelleenkäyttö, jossa juuri yli- ja aliluokan likeinen suhde rikkoo ohjelmiston modulaarisuusteriaatetta, kokoava uudelleenkäyttö sisältää myös suhteessa muuntavaan uudelleenkäyttöön enemmän olioita ja vähemmän luokkia.
Delegointi tarkoittaa periytymisen toteuttamista komposition avulla. Delegointi siirtää suorituspyynnön yliluokkaoliolle mikäli ei itse voi sitä toteuttaa, atribuuttina tulee olla viite yliluokkaolioon. Ns. "tavallisessa" periytymisessähän olio käsittelee itse operaation suorituspyynnön soveltaen yliluokassa määritettyä operaatiota. Delegaation tarjoama etu on mahdollisuus muutta olion käyttäytymistä dynaamisesti. Esimerkiksi kuvioluokan olio, jonka yliluokkana on suorakulmioluokan olio, voidaan ajoaikana vaihtaa ympyrä-yliluokan ilmentymäksi. Tällainen tarve saattaisi syntyä esimerkiksi mikäli olion tehtävänä on vaikkapa pinta-alansa laskeminen ja suorakulmion sijasta on laskettava ympyrän ala koska kuvio muuttuu ajoaikana ympyräksi.
Tällaisen dynaamisen sidonnan yhteydessä operaation suorituspyynnöllä tulee olla parametrina alkuperäisen pyynnön saanut olio.
Sovelluskehykset
(Application frameworks)
Toisiinsa liityvien luokkien kokoelmat olioihjelmoinnissa voidaan täydentää sovelluskehyksillä toimiviksi sovelluksiksi, samassa sovelluksessa voi olla useita sovelluskehyksiä..
Uudelleenkäytetään luokkien välisen yhteistyön mallia, ei siis yksittäisiä rutiineja tai tiettyä luokkaa. Sovelluskehyksissä yhdistyvät muunnelta ja kokoava uudelleenkäyttö sekä sovelluksen kontrollin uudelleen käyttö. Sovelluskehykset voidaan jakaa kokoaviin sovelluskehyksiin, joissa korostuu kokoava uudelleenkäyttö (black-box reuse) ja muuntaviin sovelluskehyksiin (white-box reuse korostuu).
Kaavioesimerkki sovelluskehyksen käytöstä:
A: kontrollin siirto kehykselle, B: dynaaminen sidonta.
Sovellusohjelmoijan koodi sisältää sovelluskohtaisia aliluokkia ja sovelluskehys yleisiä käsitteitä kuvaavia luokkia. Ohjelmoija antaa joillekin kehyksen luokille aliluokkia sekä tekee alustuskoodin, joka pitää sisällään kontrollin siirron sovelluskehykselle sekä peruskomponenttien luonnin ja alustuksen. Alustuksen jälkeen kontrolli siirtyy sovelluskehykselle. Uusissa aliluokissa annattuja operaatioita kutsutaan myös myöhäisessä sidonnassa.
Tyypillinen esimerkki sovelluskehyksestä on javakielen Abstract Windowing Toolkit, AWT, jota käytetäessä jää ohjelmoijan tehtäväksi ainoastaan luoda ilmentymiä standardeille käyttöliitymäkomponenteille.
OMT
OMT, eli olioperustainen analyysi ja suunnittelu, käsiteltiin luennoilla ja niistä on eriillinen pieni tiivistelmä. En katsonut kuitenkaan aiheelliseksi sisällyttää tähän tiivistelmään OMT:ä koska se ei kuulu kurssin vaatimuksiin eikä sitä tulla tenteissä myöskään kysymään.
Olioparadigma
Perinteinen ohjelmistokehitys, osittava (top - down)
- askel kerrallaan tarkentuvat abstraktiotasot toiminnan karkeasta kuvauksesta aina ohjelmakoodiin saakka.
- antaa ohjelmakoodille selkeän rakenteen
- ylempien tasojen kuvauksia voidaan käyttää
suoraan ohjelmiston dokumentteina
- ohjelmistokomponentit ovat riippuvaisia ylemmän tason toiminnallisista ratkaisuista
- tietorakenteet toiminnoista irrallisia
- ei kantaa tiedon strukturointiin
Ongelmia:
- pienikin muutos ylätasolla aiheuttaa ketjureaktion ja saattaa vaatia laajaa remonttia ohjelmiin
- ohjelmistokomponenteilla huono uudelleen käytettävyysaste
- ylimmän tason mahdollinen epämääräisyys
Olioperustainen (Object-oriented) ohjelmointiparadigma:
- ohjelmiston koko elinkaaren mittainen systemaattinen prosessi
- ohjelmistot kuvataan joukkona olioita, jotka eivät ole irrallisia vaan keskenään vuorovaikutuksessa
Olioista ja oliokäsitteestä
Olio on luokan ilmentymä
Olion käsite
- strukturoinnin perusyksikkö
- ei ainoastan toiminnallinen (aliohjelma)
- ei ainoastaan tietoa säilytävä (tietue)
- kapselointi eli kotelointi on keskeinen ominaisuus
- kykenee pyydettäessä suorittamaan sille ominaiset toiminot
operaatiot
- nimi
- parametreja
- toiminnan määritely
- kykenee tallentamaan tietoa olion attribuutteihin (nimettyjä tietokenttiä)
- olion tilat ovat attribuuttien arvojen yhdistelmiä
- operaation suoritus muuttaa olion tilaa
- olion piirteet: attribuutit ja operaatiot yhdessä
- olion identifioiva tunniste on viite
- olio on suojattu, käyttö on rajattu vain tiettyihin muotoihin
Täydellisesti olioperustainen ohjelma, jos sekä kaikki sen toiminnallisuus sisältyy oioiden operaatioihin ja vastaavasti myös kaikki tieto sijoittuu oioiden atribuutteihin. Täydellisesti olioperustaisen ohjelman toiminta käynnistyy juurioliossa (root object)
Puhdas oliokieli on sellainen kieli, jolla tehdyt ohjelmat ovat aina täydellisesti olioperustaisia. Tällaisia kieliä ovat mm. Java, Smalltalk ja Eiffel.
Aktiivinen olio: edustaa omaa prosessia
Koosteolio (composite object): oliolla on osinaan toisia olioita
Oliokielistä
•Alkoivat laajemman leviämisensä ajatteluun 80-luvun puolivälissäm vaativat selvää ajattelutavan muutosta ohjelmoinnissa.
•Aiemmin mm.
- Simula (Norjan valtion laskentakeskus 60 luvulla)
- Smalltalk (70-luku ja Xerox, USA)
•Hybridikielet: ohjelmointimuokattu oliosuuntaan, ei aitoja oliokieliä.
Olioajattelun perusperiaatteet
(OhjPK/ P.Hirvonen)
- abstrahointi (abstraction)
- kapselointi eli kotelointi (encapsulation)
- tiedon suojaus (information hiding)
- periytyminen (inheritance)
- polymorfismi (polymorphism)
- dynaaminen sitominen (dynamic binding)
Oliokäsitteitä
- alistettu olio
(attribuutin arvona on kokonainen olio)
- muuttujat: nimetyt tiedon tallennuspaikat.
- viitesemantiikka (muuttujien sisältönä viitteitä olioihin)
- arvosemantiikka (arvona olio)
- kohdeolio
- väliaikainen olio
- paikallinen olio
- vapaa olio
Luokka (class)
Luokka määrittelee olioiden piirteet kertomalla mitä attribuutteja ja operaatioita luokan ilmentymällä - eli siis oliolla - on. Luokka on abstraktin tyypin muoto, olio on "käyttöön otettu luokka". Luokka määrittelee tieto- ja toiminto-osista koostuvan kokonaisuuden, jolla on oma rajapinta
Abstrakti tietotyyppi (Abstract Data Type) määrittelee käyttäjille omiin ilmentymiin sovellettavat operaatiot, mutta ei määrittele toteutustapaa eikä tietorakenteita. Abstraktin tietotyypin ilmentymän määrittelee sen tuottamat palvelut.
Abstrakti tietotyyppi esitetään käyttämällä välineitä, joilla yhteenkuuluvien määrittelyjen joukko voidaan sulkea kontrolloidun rajapinnan sisään (kapselointi eli kotelointi). Esimerkki tutusta kotelointivälineestä on on moduuli. Abstraktin tietotyypin käyttö vähentää ohjelman osien keskinäistä riippuvuutta.
Abstrakti tietotyyppi on myös lähellä olion käsitettä: "tiedon (attribuutit) ja operaatioiden (tietoon liittyvän toiminnan) kokoaminen sekä abstrahointi yhdeksi yksiköksi."
Luokka puolestaan määrittelee sekä omiin ilmentymiinsä sovelletavat operaatiot, että attribuutit.
Luokka on siis eräänlainen "pidemmälle viety" abstrakti tietotyyppi, joka määrittelee paitsi toiminto- niin myös tieto-osista koostuvan kokonaisuuden, jolla on oma rajapinta. Olion attribuutti on luokan attribuutin määrittelyn ilmentymä.
Luokka ei kuitenkaan ole välttämätön olio-ohjelmoinnissa, on oliopohjaisia ohjelmointikieliä (esim. Elf ja suomalainen Kevo), joissa oliot luodaan kloonaamalla ne vanhemmista olioista.
Uusi olio luodaan luontioperaatiolla, luokkaan erikoisasemassa olevalla operaatiolla, joka varaa olion attribuuteille talletuspaikan muistissa ja palauttaa arvona viitteen muistipaikkaan. Oli asetetaan usein luonnin lisäksi samalla sopivaan alkutilaan alustusoperaatiolla eli konstruktorilla asetettamalla arvot attribuuteille. Alustusoperaation voi antaa luokalle ohjelmoija, mutta tavallisesti systeemi tuottaa sen automaattisesti.
Javakielessä jokaisella luokalla on ainakin yksi oma konstruktori (alustusoperaatio) ja vapaiden olioiden luomisen on käytössä erityinen kielen operaattori (new), joka käynnistää samalla myös luokan alustusoperaation. Mikäli konstruktoria ei anneta tekee systeemi sen siis itse ilman parametreja. Konstruktorin nimi on sama kuin vastaavan luokan.
- Luokka määritellään javassa lauseella class.
- Luokan, josta luokka on periytynyt, kertoo extends.
- Luokan tyypin määrittelee muunnin (esim. public), joka usein voidaan jättää myös pois.
- Luokan mahdollinen rajapinta ilmoitetaan implements -sanalla.
Esim. Public class Demo extends Applet implements Runnable
Luokan muuntimia javassa
• Public - luokka periytyy
- muuttujia voi osoittaa kaikista muista luokista.
• Final - luokka ei periydy
- muuttujia ja funktioita voi osoittaa kaikista muista luokista
- luokan sisältöä ei voi muuttaa
• Abstract - luokasta ei voi tehdä oliota muutoin kuin periyttämällä
- luokan funktiot eivät sisällä ohjelmakoodia
• Private - luokka ei periydy
- muuttujaa voi osoittaa vain luokasta, johon se on määritelty
• Protected - muuttujaa voi osoittaa vain aliluokasta
• Threadsafe - muuttujan arvo ei vaihdu jos kaksi prosessia käyttää sitä samaan aikaan
• Synchronized - funktiota ei voi suoritaa samanaikaisesti useampi prosessi
Luokan menetelmät eli metodit
Menetelmä: "operaation toteutuskoodi", "luokan sisäinen funktio"
Esimerkki
class Luokka
{
String jono;
int luku;
void funktio (void) //<- void -funktio
{// jotain koodia//}
}
Javassa funktio ≈ metodi eli ohjelmakoodia ei ole funktion ulkopuolella
Metodit määritellään samoin kuin C-kielen funktiot
Muuttujat, jotka määritellään metodien parametrilistassa eivät voi kätkeytyä määritetyiltä muuttujilta!
Esimerkki:
class Luokka
{
String s;
int luku;
void funktio (int p{
int p; // virheilmoitus
}
}
Javassa - jokainen uusi luokka luo uuden tyypin
- jokainen uusi luokka periytyy jostain luokasta
Luokan käyttöönotto
(olion luominen)
• Olion määrittely:
class Olio; // vain määrittely
(luokka)
• Muisti varataan new operaattorilla:
Olio = new luokka ();
• Määrittely mikäli kyseessä on tauluko-olio:
class Olio [] = new Luokka [100]
• Kun olio on rakennettu niin sen funktiota voidaan kutsua esimerkiksi:
Funktio (1); <- sisältä
Olio.Funktio (1); <- ulkopuolelta
Esimerkki:
package Ihmiset;
import java.lang.String
import java.lang.System
public class Henkilo {
public Henkilo() {
}
String nimi;
int ika = 0; // attribuutti ika
void ristiminen (String n) {
nimi = new String (n);
// asetetaan atribuutti nimi viittaamaan uuteen}
// String luokan olioonvoid tervehdi () {
System.out.println(" Terve, olen " + nimi);
}
void vanhene () {ika++;}
}
Uusien olioiden luominen luokan pohjalta:
class J{
...
Henkilo eeva;
Henkilo aatami;
...
void kuudespaiva () {
eeva = new Henkilo();
aatami = new Henkilo ();
eeva.ristiminen ("Eeva");
aatami.ristiminen ("Aatami");
}
void aika () {
eeva.tervehdi ();
aatami.tervehdi ();
for (int vuosi = 0; vuosi <= 100000; vuosi++) {
if (vuosi < 1000) {
eeva.vanhene ();
aatami.vanhene ();
}
if (vuosi == 1000) {
eeva = null;
aatami = null;
}
}
}}
Luokan J käyttö luokan Paaohjelma operaatiossa main:
class Paaohjelma
public static void main (String args[]) {
J ruler;
ruler = new J();
ruler.kuudespaiva();
ruler.aika();
}}