22
Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6 Kevätlukukausi 2010 Jyväskylän yliopisto Tietojenkäsittelytieteiden laitos Markku Sakkinen

Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

  • Upload
    gaston

  • View
    33

  • Download
    0

Embed Size (px)

DESCRIPTION

Kevätlukukausi 2010 Jyväskylän yliopisto Tietojenkäsittelytieteiden laitos Markku Sakkinen. Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6. Perinteisissä oliokeskeisissä ohjelmistokehyksisssä laajentaminen perustuu ensi sijassa periytymiseen - PowerPoint PPT Presentation

Citation preview

Page 1: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Komponenttipohjainen ohjelmistotekniikka (TJTSS56)

Osa 6

Kevätlukukausi 2010Jyväskylän yliopisto

Tietojenkäsittelytieteiden laitosMarkku Sakkinen

Page 2: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Polymorfisuus (jatkoa)Riippumattoman laajennettavuuden ulottuvuuksia

Szyperski, kohta 6.9

Perinteisissä oliokeskeisissä ohjelmistokehyksisssä laajentaminen perustuu ensi sijassa periytymiseen

• Kehyksen luokille (yleensä abstrakteille) määritellään aliluokkia.• Jos jokin kehyksen abstraktio ei sovi rakennettavaan sovellukseen

tarpeeksi hyvin, aliluokat eivät toteuta korvattavuutta eli periytyminen ei ole aitoa erikoistamista.

• Tämä on mahdollista, koska toteutuksen perintä nykyisissä kielissä ei vaadikaan aliluokilta yliluokkien mukaista semantiikkaa.

Perinteiset ohjelmistokehykset ovat vain kehitysaikaisia ”olioita”, jotka eivät ole toimivassa ohjelmistossa erillisinä näkyvissä.

• Huomattavia ongelmia periytymisen kyseenalaisesta käytöstä tulee vasta sitten, jos ohjelmisto haluttaisiin siirtää kehyksen uuteen versioon.

• Kehys ja siihen perustuva ohjelmisto eivät ole toisistaan riippumattomasti laajennettavia.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 63. 3. 2010 2

Page 3: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Riippumattoman laajennettavuuden ulottuvuuksia (jatkoa)Riippumattomasti laajennettavissa komponenttijärjestelmissä tilanne on

hyvin toisenlainen.• Jokaisessa komponentissa täytyy varautua siihen, että sen

käyttämiä tai palvelemia komponentteja vaihdetaan jopa ajon aikana.

• Sopimusten tarkka toteuttaminen on välttämätöntä.• Tarvitaan selvät määritelmät siitä, mitä ja miten voidaan laajentaa.

Jokaista tällaisen järjestelmän piirrettä, jota voidaan laajentaa erikseen, kutsutaan (riippumattoman) laajennettavuuden ulottuvuudeksi (dimensioksi).

• Olisi hyvä, että eri ulottuvuudet olisivat ”ortogonaalisia”.• Muuten voidaan samanlainen vaikutus saada laajentamalla eri

ulottuvuuksissa.• Tärkeämpää on kuitenkin, että laajentamismahdollisuudet ovat

riittävät ohjelmiston evoluutiotarpeisiin nähden.• Yleensä täysi ortogonaalisuus ei ole mahdollinen.• Esim. jos järjestelmässä on laajennettavat abstraktiot olioiden

sarjallistamiselle ja säilyvyydelle, niillä on luultavasti jotain yhteistä.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 63. 3. 2010 3

Page 4: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Riippumattoman laajennettavuuden ulottuvuuksia (jatkoa)Riippumattomasti laajennettavassa järjestelmissä täytyy olla jokin

perusrakenne, jota sitten laajennetaan.• Eri laajennusulottuvuuksien välisiä rajapintoja kutsutaan

pullonkaularajapinnoiksi (bottleneck interfaces).• Erityisesti näiden rajapintojen täytyy olla muuttumattomia.• Huonosti suunnitellussa komponenttikehyksessä eri ulottuvuuksiin

kuuluvat laajennuskomponentit voivat tarvita muitakin yhteyksiä toisiinsa.

Ainokaiskonfiguraatio (singleton configuration)• Joskus vaaditaan, että järjestelmässä on täsmälleen yksi tai

enintään yksi tiettyä ulottuvuutta laajentava komponentti.• Esimerkki voisi olla turvallisuudenhallitsin.Rinnakkaisiksi laajennoksiksi sanotaan sellaisia komponentteja, jotka

laajentavat samaa ulottuvuutta.Ortogonaalisiksi laajennoksiksi sanotaan sellaisia komponentteja, jotka

laajentavat eri ulottuvuuksia.Myös rekursiivinen laajentaminen on mahdollista.• Jokin komponentti voi itse olla myös komponenttikehys.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 63. 3. 2010 4

Page 5: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Evoluutio vastaan rajapintojen ja sopimusten muuttumattomuus

Szyperski, kohta 6.10

Sopimus (rajapinta ja sen semantiikan määrittely) yhdistää riippumattomasti kehittyviä palvelimia ja asiakkaita.

• Kun sopimus on julkaistu, sitä ei pitäisi enää muuttaa.• Palveluntarjoaja voi lakata tarjoamasta jotakin sopimusta, mutta

se menettää silloin ne asiakkaat, jotka tarvitsevat juuri tämän sopimuksen mukaisia palveluja.

• Palveluntarjoaja ei voi muuttaa sopimuksen spesifikaatiota (semantiikan määrittelyä).

• Asiakas ei voi muuttaa omaa sopimuksen tulkintaansa, tai sille voi aiheutua virheitä palvelun käytössä.

• Jotta sopimuksesta voidaan edes keskustella, siihen on pystyttävä viittaamaan yksikäsitteisesti.

• Yleensä käytetään rajapinnan nimeä viitaamaan koko sopimukseen.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 63. 3. 2010 5

Page 6: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Evoluutio vastaan rajapintojen ja sopimusten muuttumattomuus (jatkoa)

Jos sopimusta kuitenkin muutetaan, muutos voi olla kahta laatua:• Syntaktinen: rajapinta muuttuu (esim. jonkin metodin parametrien

järjestys).• Semanttinen: spesifikaatio muuttuu.• Monet muutokset koskevat tietysti sekä syntaksia että

semantiikkaa, esim. uuden metodin lisääminen.Olio-ohjelmoinnissa palvelinluokka ”hallitsee” sopimusta.• Puhutaan ”särkyvän yliluokan” (fragile base class) ongelmasta.

Sopimusten evoluutio on mahdollista silloin, kun ne ovat vain jonkin projektin tai organisaation sisäisiä.

• Kun tehdään muutos, voidaan tarkistaa kaikki asiakkaat ja palvelimet, joihin se vaikuttaa.

Joissakin komponenttijärjestelmissä sallitaan rajapintojen versiointi.• Entiset asiakkaat voivat käyttää vanhaa versiota, vaikka

uudempikin on tarjolla.• Esim. entisessä IBM:n SOMissa (System Object Model) uudessa

versiossa rajapintaan sai vain lisätä uusia metodeja.Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 3. 3. 2010 6

Page 7: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Evoluutio vastaan rajapintojen ja sopimusten muuttumattomuus (jatkoa)

Sopimus voi olla määräaikainen.• Varsin luonnollista, jos sopimukseen liittyy lisensiointi.• Asiakkaat tietävät, että sopimuksen mukaiset palvelut voivat

loppua määräpäivänä.• Palveluntarjoajat tietävät, että velvollisuus tarjota palveluja

loppuu määräpäivänä.• Sopimuksen voimassaoloa entisellään voidaan päättää jatkaakin.• Voidaan myös tehdä uusi, muunnettu sopimus.

Korkeamman tason määräykset voivat vaatia muutoksia sopimuksiin, kuten lainsäädäntö ym. liike-elämän sopimuksiin.

• Kansalliset ja kansainväliset standardit.• Määräävässä asemassa oleva yhtiö.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 3. 3. 2010 7

Page 8: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Muita polymorfismin muotoja

Monimetodit (multimethods, multiple dispatching)• Joissakin oliokielissä metodinkutsun dynaaminen sidonta voi

perustua myös parametrien eikä vain kohdeolion todellisiin (dynaamisiin) tyyppeihin.

• Helpottaa asiakkaiden ohjelmointia monissa tilanteissa.• Toisaalta aiheuttaa sekä periaatteellisia että toteutuksellisia

ongelmia.

Kuormitus (overloading)• Monissa oliokielissä (esim. C++:ssa, Javassa ja C#:ssa) ja muissa

kielissä.• Samalla nimellä voi olla useita eri metodeja (samassa luokassa),

jotka erotetaan toisistaan parametrien tyyppien perusteella.• Oikea vaihtoehto tunnistetaan käännösaikana (salakavala ero

monimetodeihin).• Kutsutaan joskus ad hoc -polymorfismiksi.• Metodeilla olisi hyvä olla samanlainen semantiikka.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 3. 3. 2010 8

Page 9: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Muita polymorfismin muotoja (jatkoa)Geneerisyys (genericity)• Atk-sanakirja suosittelee myös termiä ”malli-” adjektiivin

”geneerinen” vastineeksi.• Myös ”parametrinen polymorfisuus” (parametric polymorphism).• Luokalla (tai pakkauksella tms.) voi olla muodollisia geneerisiä

parametrejä (malliparametrejä).• Varsinainen luokka (tms.) syntyy vasta instantioimalla

(generoimalla) geneerinen luokka (luokkamalli) sopivilla todellisilla parametreillä.

• Instantiointi tapahtuu käännösaikana.• Geneeriset parametrit ovat yleensä luokkia (tai muita tyyppejä).• Esim. Adassa ja C++:ssa myös tietotyyppien vakioarvot ovat

mahdollisia.

Syntaktinen geneerisyys• C++:ssa geneeriset luokat ja aliohjelmat (templates) ovat

makrojen kaltaisia.• Mallin tasolla kääntäjä voi todeta vain syntaktiset virheet.• Kelvollisuus (mm. tyypitys) ja semantiikka selviävät vasta kutakin

instantiointia käännettäessä.Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 3. 3. 2010 9

Page 10: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Muita polymorfismin muotoja (jatkoa)

Semanttinen geneerisyys• Jo mallilla (geneerisellä luokalla tms.) on yksikäsitteinen

semantiikka, jonka kääntäjä selvittää.• Geneerisen koodin pitää olla kelvollista kaikille mahdollisille

todellisille parametreille.• Ellei jollekin muodolliselle parametrille määritellä rajoitteita

(constraints), sen käyttömahdollisuudet ovat vähäiset.• Sopii ensi sijassa säiliö- ja kokoelmaluokille.

• Oliokielissä tavallisin rajoite on jokin rajaluokka, jonka jälkeläinen todellisen parametrin pitää olla (mm. Eiffelissä ja Javassa).

• Joissakin kielissä (mm. Eiffelissä ja Javassa) voidaan kääntää jo geneerinen luokka eikä jokaista generoitua luokkaa erikseen.

• Tämä sekä edellyttää joitakin rajoituksia parametreille että aiheuttaa joitakin rajoituksia generoitujen luokkien käytölle.

Perhepolymorfisuus (family polymorphism)• Erik Ernstin esittelemä (ECOOP 2001:ssä) uusi lähestymistapa,

joka pyrkii yhdistämään periytymisen ja geneerisyyden edut.• Vaikuttaa hyvin lupaavalta varsinkin komponenteille.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 3. 3. 2010 10

Page 11: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän korvaaminen koostamisellaSzyperski, luku 7

Tässä luvussa tutkitaan perinnän erilaisia merkityksiä oliokielissä ja sitä, missä määrin toteutuksen perinnän sijasta olisi parempi käyttää koostamista (composition).

• Periytymistä voidaan pitää luokkien välisenä koostamisena, joten tässä verrataan luokkien ja olioiden koostamista toisiinsa.

• Erityisesti käsitellään särkyvän yliluokan ongelmaa.• Kurinalainen periytyminen (disciplined inheritance) voi estää

joitakin ongelmia.• Juuri tuo oli minun ECOOP’89:ssä julkaistun artikkelini nimi.

• Siinä pyrin tarkastelemaan perintään koostamisen erikoistapauksena.• Työnimenä oli ”Inheritance considered harmful”.

Periytymisen kolme tärkeintä aspektia (ainakin Szyperskin mielestä):• Toteutuksen perintä eli aliluokkasuhde (subclassing)• Rajapinnan perintä eli alityyppisuhde (subtyping)• Korvattavuus (substitutability)

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 3. 3. 2010 11

Page 12: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän korvaaminen koostamisella (jatkoa)

Useimmissa oliokielissä toteutuksen ja rajapinnan perintä ovat erottamattomasti yhdessä.

• Pelkkää rajapintaa ei voida periä sellaisesta luokasta, jossa on yhtään toteutusta mukana.

• On joitakin kieliä, joissa perintä ja alityyppisuhde on erotettu toisistaan.

• Erityiset rajapinnanmäärittelykielet (esim. COMissa ja CORBAssa) eivät ota ollenkaan kantaa toteutukseen.

• Joissakin kielissä on mahdollista kertoa, että aliluokka perii yliluokalta vain toteutuksen.

• C++:ssa yksityinen perintä – jopa oletuksena!• Mahdollisuus on lisätty äskettäin Eiffeliin (non-conforming inheritance).

Korvattavuus on näistä ominaisuuksista vaikein määritellä ja toteuttaa.• Useimmissa kielissä se tavallaan oletetaan, mutta jää ohjelmoijan

vastuulle.• C++:ssa ja Eiffelissä aliluokan olio ei voi korvata yksityisesti tai

”mukautumattomasti” perityn yliluokan oliota.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 3. 3. 2010 12

Page 13: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän vivahteitaOsittain Szyperski, kohta 7.2

Moniperintä (multiple inheritance)

Kaksi toisistaan riippumatonta jakoa (ainakin).• Peritäänkö rajapinta, toteutus vai molemmat?• Onko perittävillä luokilla tai rajapinnoilla yhteisiä esivanhempia

(haarautuva moniperintä – fork-join, repeated, diamond inheritance) vai ei (riippumaton moniperintä – independent multiple inheritance) ?

Tärkein lähestymistapojen jako: käsitelläänkö kunkin yliluokan uusia (ei perittyjä) ominaisuuksia yhtenä kokonaisuutena (alioliokeskeinen) vai ei (atribuuttikeskeinen)?

• Useimmat moniperintäkielet noudattavat atribuuttimallia – myös Java rajapintojen periytymisessä.

• Puhtaassa atribuuttimallissa samaistetaan eri yliluokista perityt atribuutit ja metodit, jos niillä on sama nimi ja tyyppi (tai kutsumuoto).

• Eiffelissä samaistaminen tapahtuu vain haarautuvassa perinnässä, ja se voidaan estää uudelleennimeämisellä.

• Tärkein alioliomallia noudattava kieli on C++.Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 4. 3. 2010 13

Page 14: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän vivahteita (jatkoa)

Atribuuttipohjaisen lähestymistavan lisäjako: otetaanko huomioon koko periytymisrakenne (verkkoperiaate) vai pelkästään välittömät yliluokat (lineaarinen periaate)?

• Tällä kurssilla pidämme oletuksena verkkoperiaattetta, jota ainakin useimmat staattisesti tyypitetyt kielet noudattavat.

• Seuraavassa esitetään lineaarisen lähestymistavan erikoisominaisuuksia (hieman yksinkertaistaen).

• Riippumattomalla ja haarautuvalla moniperinnällä ei ole eroa.• Yleensä perintä linearisoidaan niin, että luokan määritelmässä

mainittujen yliluokkien järjestys on merkitsevä.• Samannimisistä ominaisuuksista peritään automaattisesti vain se,

jonka luokka on järjestyksessä ensimmäisenä.• Voi aiheuttaa yllättäviä tilanteita mutkikkaissa

periytymisverkoissa.• Vallitseva (tai ainakin suosittu) Lisp-pohjaisissa oliokielissä:

Flavors, CLOS (Common Lisp Object System) ym.• Näissä kielissä ei yleensä ole staattista tyypitystä.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 4. 3. 2010 14

Page 15: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän vivahteita (jatkoa)Riippumaton moniperintä on haarautuvaa yksinkertaisempi tapaus.• Useimmissa oliokielissä on kaikkien luokkien yhteinen yliluokka,

joka täytyy jättää ottamatta huomioon, jottei kaikkea moniperintää tarvitsisi käsitellä haarautuvana.

• Atribuuttikeskeisessä periaatteessa vahingossa tapahtuva ominaisuuksien samaistuminen voi kuitenkin aiheuttaa salakavalia virheitä.

• Uudelleennimeämisen mahdollisuudella voitaisiin sekä korjata tuollaisia tilanteita että sallia erinimistenkin perittyjen ominaisuuksien samaistaminen.

• Toisaalta moniperintä ei ole sallittu, jos perittävien samannimisten ominaisuuksien tyypit tai kutsumuodot ovat erilaisia – paitsi jos kuormitus on mahdollinen.

• Javan rajapintojen moniperintä ei ole sallittu, jos perittävien samannimisten metodien kutsumuodoissa eroaa vain tulostyyppi.

• Jos rajapinta käsittää myös esi- ja jälkiehdot, niiden välillä voi hyvin helposti olla ristiriitoja.

• Lineaarisessa moniperinnässä samannimisten ominaisuuksien ristiriidat eivät vaikuta, koska vain ensimmäinen niistä otetaan huomioon.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 4. 3. 2010 15

Page 16: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän vivahteita (jatkoa)Haarautuva moniperintä on vaikeampi ja mielenkiintoisempi tapaus.• Nimitys ”vinoneliöperintä” (diamond inheritance) johtuu

luonnollisesti luokkakaaviosta.• Oli yhtenä aiheena vuoden 1989 ECOOP-artikkelissani.• OOPSLA 2009 -konferenssissa oli jälleen yksi artikkeli, jossa

esitettiin uutta kielen mekanismia tähän.• Ja taistelu jatkuu…Perusongelma: tuleeko kahta eri kautta peritystä ominaisuudesta tai

alioliosta aliluokassa yksi vai kaksi?• Atribuuttikeskeisessä perinnässä aina yksi, ellei

uudelleennimeäminen ole mahdollista.• Alioliokeskeisessä perinnässä monistaminen (kaksi alioliota) on

helpompi toteuttaa kuin jakaminen (yksi aliolio).• C++:ssa oletus, jakaminen virtual-määreellä.• Jakavan ja monistavan perinnän yhdistelmät voivat C++:ssa johtaa varsin patologisiin luokkarakenteisiin.• Niiden vuoksi ”virtuaalisen” yliluokan tyyppistä viitettä ei voida muuntaa minkään aliluokan tyyppiseksi – yksinkertaisissakaan periytymisrakenteissa.

• Jakaminen vastaa paremmin periytymisen käsitteellistä merkitystä, varsinkin jos halutaan korvattavuutta.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 4. 3. 2010 16

Page 17: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän vivahteita (jatkoa)

Tilanne on yksinkertaisin, kun peritään vain rajapinta.• Mikäli perinnässä sallitaan metodin parametrien tai tuloksen

tyypin tai esi- ja jälkiehtojen uudelleenmäärittely, voi kuitenkin aiheutua ristiriita, joka estää jakavan moniperinnän.

Atribuutin (aliolioperiaatteessa koko aliolion) haarautuva perintä:• Jakava perintä on yhtä ongelmaton kuin rajapinnan tapauksessa.• Monistavassa perinnässä korvattavuus kärsii: jos aliluokan oliota

käsitellään yhteisen yliluokan oliona, kumpi atribuutti valitaan?

Toteutetun metodin haarautuva perintä:• Jo jakavassa perinnässä tulee pieni ongelma, jos

uudelleenmäärittelyjen takia perittävinä on kaksi eri toteutusta.• Useimmat kielet vaativat tällöin uudelleenmäärittelyn aliluokassa.• Perittyjen metodien kutsuminen (super) voi helposti aiheuttaa

alkuperäisen metodin kutsumisen kahteen kertaan. • Monistavassa perinnässä on lisäksi sama ongelma kuin

atribuutilla.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 4. 3. 2010 17

Page 18: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän vivahteita (jatkoa)

Lisukkeet (sekoitteet?) (mixins)

Jo Flavors-kielessä (Moon, OOPSLA’86) otettiin käyttöön lisukeluokat.• Tarkoitettuja täydentämään muita luokkia, eivät voi tuottaa

ilmentymiä yksinään.• Luonnehdittu myös ”abstrakteiksi aliluokiksi”, mutta niistä

peritään ainakin ensi sijassa toteutusta eikä rajapintaa.• Dynaamisesti tyypitetyssä kielessä, jossa noudatetaan lineaarista

moniperintää, lisukkeiden käyttöön tarvitaan hyvin vähän byrokratiaa.

• Uusi luokka voi periä mielivaltaisen joukon tavallisia ja lisukeluokkia.

• Jos luokka perii tai toteuttaa itse ainakin kaikki ne metodit, joita sen omat ja perityt metodit kutsuvat kohdeoliolle, se on kelvollinen konkreetti luokka.

• Dynaamisessa kielessä tätäkään ei yleensä voida todeta staattisesti; tarkoittaa, että virhettä ”method not found” ei tapahdu ajon aikana.

• Järkevä semantiikka ei tietenkään toteudu automaattisesti.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 4. 3. 2010 18

Page 19: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän vivahteita (jatkoa)Esimerkki: Kuvitellaan, että olisi olemassa laajennettu kieli Mixin Java (pitemmälle vietynä kuin kirjassa). Määritellään alkeellinen ikkunaluokka lisukeluokkien avulla. Ensin kolme rajapintaa ikkunan eri aspekteille:

interface DrawWindow { void drawWindow ();}

interface DrawBorders { void drawBorders (); void handleMouse (Event ev);}

interface DrawContents { void drawContents (); Rect getVisibleSection (); Rect getContentsBox (); void scrollTo (Rect newVisible);}

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 5. 3. 2010 19

Page 20: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän vivahteita (jatkoa)Sitten koko ikkunan rajapinta (COMissa tämä voisi olla kategoria):

interface Window extends DrawWindow, DrawBorders, DrawContents { }

Sitten lisukeluokka kullekin suppealle rajapinnalle:

mixin class StdWindowShell implements DrawWindow requires DrawBorders, DrawContents { void drawWindow () { drawBorders (); drawContents (); }}

mixin class TextWindowContents implements DrawContents void drawContents () { . . . } Rect getVisibleSection () { . . . } Rect getContentsBox () { . . . } void scrollTo (Rect newVisible) { . . . }}Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 5. 3. 2010 20

Page 21: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän vivahteita (jatkoa)mixin class MotifWindowBorders implements DrawBorders { requires DrawContents { void drawBorders () { . . . // draw title bar Rect visible = getVisibleSection (); Rect total = getContentsBox (); . . . // draw scroll bars } void handleMouse (Event ev); . . . if ("scroll bar thumb moved") { . . . // compute new visible region scrollTo (newVisible); } . . . }}

Ainakin luokassa TextWindowContents täytyy tietysti olla myös joitakin atribuutteja, jotta sen metodit voidaan toteuttaa.

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 5. 3. 2010 21

Page 22: Komponenttipohjainen ohjelmistotekniikka (TJTSS56) Osa 6

Perinnän vivahteita (jatkoa)

Komponenttipohjainen ohjelmistotekniikka (Markku Sakkinen) – Osa 6 5. 3. 2010 22

Lisukeluokan lauseella requires kerrotaan, mitä rajapintoja se vaatii jokaisessa sen perivässä (suoraan tai välillisesti) konkreetissa luokassa olevan toteutettuina.• Kuten komponentin vaatimat rajapinnat.• Tällaista ei tarvita dynaamisissa kielissä.

Lopuksi voidaan luoda konkreetti tavallinen luokka yksinkertaisesti perimällä kaikki lisukkeet.• Yleensä lisukkeita käyttävässä luokassa on omiakin ominaisuuksia.

class MotifTextWindow implements Window extends StdWindowShell, MotifWindowBorders, TextWindowContents { }