Tietorakenteet ja algoritmit Abstrakti tietotyyppi komponenttina Komponentin kriteerit Täyttääkö ADT komponentin kriteerit Millä ehdoilla kriteerit täyttyvät Yleisyyden tarkastelua funktion read_point avulla Hyvä ohjelmointitapa ADT:n käytössä Erillinen kääntäminen ja linkkaus Lisää etuja abstraktion ja ADT:n käytöstä Muita nimityksiä asialle Vertailu C:nja C++:n välillä ADT:n toteutuksessa 1
Abstrakti tietotyyppi komponenttina Abstrakti tietotyyppi on komponentti (ohjelmistokomponentti). Vai onko? Mikä tekee komponentista komponentin? Vertaus hardware komponenttiin: 1) Voidaan käyttää uudelleen sellaisenaan rakennuspalikkana erilaisissa laitteissa. 2) Käyttöön tarvitaan vain interface-tieto. 3) Komponentti on kompakti, musta laatikko, sisäistä toteutusta ei näy. 4) Komponentti voidaan vaihtaa toiseen parempaan, ilman että muuta laitteistoa muutetaan ympärillä, edellyttäen että interface on uudella komponentilla sama. Osoitetaan, että nämä kaikki ominaisuudet toteutuvat ADT pisteellä. 2
Voidaan käyttää sellaisenaan muissa sovelluksissa ADT pistettä tulee voida käyttää sellaisenaan esimerkiksi äskeisessä "suunnistajan sovelluksessa ympyröitä käsittelevässä sovelluksessa keskipisteenä kolmioita käsittelevässä sovelluksessa kolmion kärkipisteinä pelisovelluksessa vaikka laivan paikkana ruudulla matkailusovelluksessa reitin välietappipisteinä jne Vaatimuksen 1 edellytyksenä on, että komponentti (ADT) on hyvin suunniteltu ja sillä on riittävä valikoima oikein valittuja operaatiofunktioita. Esimerkkiohjelma, kuinka viime kerralla kehitettyä adt pistettä voidaan käyttää reittiohjelman toteutuksessa, on seuraavalla sivulla. Myöhemmin nähdään myös kuinka adt pistettä voidaan käyttää adt ympyrän keskipisteenä. 3
Esimerkki ADT pisteen käytöstä toisessa sovelluksessa int main(void) { Tpoint route[10]; int n, i; float tot_mileage; Katso myös char promt[20]; sivut 8 ja 9 scanf( %d, &n); for (i = 0 ; i < n ; i++) { sprintf(promt, Anna %d. etappipiste:, i + 1); read_point(&route[i], promt); tot_mileage = 0.0; for (i = 0 ; i < n-1 ; i++) { tot_mileage = tot_mileage + distance(route[i], route[i + 1] ); jne 4
Käyttöön tarvitaan vain interface-tieto Adt:n käyttämiseen sovelluksessa tarvitaan vain sen interface-tieto. Interface-tietoa on vain Tietotyypin nimi Sen käsittelyfunktioiden prototyypit Käyttämiseen ei tarvita tietotyypin sisäistä rakennetta eikä käsittelyfunktioiden toteutustavan tuntemusta. Katso ohjelma edellisellä sivulla. Vaikka tietotyypin määrittelyssä näkyy sen sisäinen rakenne (esimerkiksi tietueen kentät), niitä ei tarvita käyttötasolla, eikä niitä hyvän tavan mukaan saa käyttää. Niitä käsitellään vain käsittelyfunktioiden toteutuksissa. Käsittelyfunktion prototyyppi on riittävä tieto funktion käyttämiseen. Funktion prototyyppi on funktion käyttäjälle täydellinen funktion käyttöohje. Huomautus. Funktion prototyypillä on toinenkin tehtävä kuin toimia sen käyttöohjeena. Kääntäjä tarkistaa funktion kutsut prototyypin perusteella ja antaa virheilmoituksen, jos parametreja ei ole oikea määrä tai jos ne eivät ole oikeaa tyyppiä. 5
Toteutus voidaan kätkeä mustaan laatikkoon Komponentti on kompakti, musta laatikko, sisäistä toteutusta ei edes näy. Tämä vaatimus saadaan toteutettua laittamalla ADT:n käsittelyfunktioiden toteutukset omaan tiedostoon ja samoin ADT:tä käyttävän sovelluksen toteutus omaansa. Lisäksi tietotyypin määrittely ja sen käsittelyfunktioiden prototyypit laitetaan omaan header tiedostoon (otsikkotiedostoon) koska niitä eli interface-tietoa tarvitaan sekä sovelluksessa että käsittelyfunktioiden toteutuksissa. Kun sitten käsittelyfunktioiden toteutukset sisältävä tiedosto käännetään, saadaan objektitiedosto, jota voidaan pitää komponentin mustana laatikkona. Toteutuksen source-koodia ei silloin enää tarvita sovellusten rakentamisessa. Tarvitaan vain "musta laatikko" eli käännetty objektimuotoinen moduli, joka linkataan sovellukseen. Katso myös sivu XX. 6
Musta laatikko ADT pisteen tapauksessa Edellä esitelty suunnistajan sovellus voidaan jakaa seuraaviin tiedostoihin: point.h (sisältää pisteen interfacen, tyypin määrittelyn ja operaatiofunktioiden protot) point.c (sisältää pisteen käyttöfunktioiden toteutukset) suunnistus.c (sisältää sovelluksen) Tiedosto point.h incluudataan tiedostoihin point.c ja suunnistus.c. Tiedosto point.c käännetään ja saadaan point.obj (musta laatikko). Tiedosto suunnistus (tai muu pistettä käyttävä sovellus) käännetään ja siihen linkataan point.obj (tiedostoa point.c ei enää tarvita). Tästä jakamisesta saadaan muitakin hyötyjä: 1. Editorissa pidettävä tieto pysyy kohtuullisena kooltaan. 2. Ohjelman teko voidaan jakaa eri henkilöille. Sovellusohjelmoija ja komponenttiohjelmoija suunnittelevat yhdessä intefacen, jonka jälkeen molemmat voivat työskennellä rinnakkain itsenäisesti 7
Separate compiling and linking together 8
ADT voidaan vaihtaa toisenlaiseen toteutukseen Komponentti voidaan vaihtaa toisenlaiseen toteutukseen ilman, että muuta laitteistoa muutetaan ympärillä, edellyttäen että interface on uudella komponentilla sama. ADT:n tapauksessa edellytyksenä vaihdettavuuteen on, että komponentti on suunniteltu siten ja sovellus kirjoitettu siten, että sovellus on riippumaton komponentin toteutustavasta, niin kauan kuin interface pysyy samana. Esimerkiksi siirtyminen pisteen paikan uuteen mittaustapaan mittalaitteella, jonka tiedot luetaan automaattisesti sarjalinjalta ei vaikuta sovellustasolla ohjelmaan. Myöskään siirtyminen pisteen paikan esittämiseen sisäisesti napakoordinaateissa ei vaikuta sovellustasolla. Eikä myöskään pisteen sisäisen esitystavan muuttaminen taulukoksi. Samoin jos ajan sisäisessä esityksessä siirrytään tallentamaan aika minuutteina keskiyöstä, ei sovellukseen tarvita muutosta. 9
Edellytykset vaihdettavuuteen Vaatimuksen 4 toteutumiseen eli komponentin helppoon vaihtoon on edellytyksenä hyvän ohjelmointitavan noudattaminen. Hyvä ohjelmointitapa: Ei suoraa viittausta sovelluksessa tietotyypin sisäiseen rakenteeseen. Tietotyyppiä käsitellään vain "kokonaisena" sen operaatiofunktioilla. Esimerkkeinä siitä, että komponentti voidaan vaihtaa muuttamatta sovellustasolla mitään, tarkasteltiin kahta tapausta: 1) siirrytään napakoordinaatistoon ja 2) määritellään Tpiste taulukkona typedef float Tpiste[2]; Kummastakaan muutoksesta ei seuraa muutostarvetta sovellustasolle eli main-funktioon suunnistajan ohjelmassa (tai muissa). Esimerkki komponentin väärästä käyttötavasta, joka estää helpon vaihhdettavuuden: int main(void) { Tpoint p1, p2; p1.x = 10; Pilaa vaihdettavuuden 10
Yleisyyden tarkastelua funktion read_point avulla 1/2 Ratkaisu 1. Käytetään funktioita void read_origin(tpoint *origin) ja void read_destination(tpoint *destination); Ratkaisu 2. Käytetään funktiota void read_points(tpoint *p1, Tpoint *p2); void read_points(tpoint *p1, Tpoint *p2) { printf("\nenter origin"); scanf("%f%f", &p1->x, &p1->y); printf("\nenter destination"); scanf("%f%f", &p2->x, &p2->y); a) pisteen lukeminen ohjelmoidaan kahdesti b) sisältää sovellusspesifistä koodia (yleisyys kärsii) 11
Yleisyyden tarkastelua funktion read_point avulla 2/2 Ratkaisu 3. Käytetään funktiota void read_point(tpoint *p); void read_point(tpoint *p) { scanf("%f%f", &p->x, &p->y); Voidaan käyttää uudelleen melko hyvin. Ainoastaan kehote voi olla ongelma. Ratkaisu 4. Viimeisenä vaiheena oli funktio void read_point(tpoint *p, const char *prompt) { printf("%s", prompt); scanf("%f%f", &p->x, &p->y); ) Tässä on mahdollista jopa ajonaikana generoida haluttu kehote. 12
Lisää abstraktion etuja monimutkaisuuden hallinta helpottuu tekee mahdolliseksi laatia laajoja ohjelmia tekee mahdolliseksi paloitella tehtävä pienempiin osiin tekee mahdolliseksi jakaa ohjelmointityö ja edetä askelittain ohjelmista tulee luettavampia ohjelmien verifiointi tulee mahdolliseksi testaus helpottuu ohjelmien ylläpito ja jatkokehitys helpottuu tehtyjen ohjelmanosien uudelleenkäyttö tehostuu (ohjelmiston rakennuskomponentit) 13
Muita nimityksiä samalle asialle abstraction information hiding black box thinking programming in large 14
Tiedon kätkennän lisävalaistusta Tiedon kätkennän lisävalaistusta: read_point(&origin, "Enter origin"); origin is upper level concept for location (point), We have hided he details how it is represented internally read_point is an upper level concep for reading (it tells what we do). We have hided the details how reading is done. Function prototype tells everything about the black box function name tells what parameters tell input and output 15
ADT as a structure in C //Datatype definitions typedef struct { float x; float y; Tpoint; //Operation function prototypes void read_point(tpoint *p, char *prompt ); void print_point(tpoint p); float calculate_dist(tpoint p1, Tpoint p2); //Application void main(void) { Tpoint p1, p2; float dist; read_point(&p1, "Enter point 1"); read_point(&p2, "Enter point 2"); dist = calculate_dist(p1,p2); printf("distance is %f", dist); //Operation function implementations void read_point(tpoint *p, char *prompt) { printf("\n %s", prompt); scanf("%f", & p->x ); scanf("%f", & p->y ); void print_point(tpoint p) {... float calculate_dist(tpoint p1, Tpoint p2) {... ADT C:ssä ja C++:ssa ADT as a class in C++ //class definitions class Tpoint { private: float x; float y; public: void read(char *prompt ); void print(); float calculate_dist(tpoint p2); ; //Application void main(void) { Tpoint p1, p2; float dist; p1.read("enter point 1"); p2.read("enter point 2"); dist = p1.calculate_dist(p2); cout << "Distance is << dist; //Operation function implementations void Tpoint::read(char *prompt) { cout << endl << prompt ; cin >> x; cin >> y; void Tpoint::print() {... float Tpoint::calculate_dist( Tpoint p2) {...