TIE-20200 Ohjelmistojen suunnittelu Luento 8: Kirjastot, rakennustusjatkot jne. TIE-20200 Samuel Lahtinen 1
Ajankohtaista Suunnittelusessioita vielä jäljellä Viikkoharkkakertoja jäljellä vielä 2 kpl Viikkoharjoitusaikamuutos: Keskiviikon harkka 10-12 (ei 9-11) Viikkoharjoituksissa kirjastojen käyttöä & toteuttamista
Ohjelmassa tänään Viime viikon rääppeitä, rakennuttajajutut loppuun Kirjastoista hippunen Suunnittelusessioiden siivittämänä vähän kaavioasiaa
Kaavioista Mieti aina mitä kaaviolla/kuvalla on tarkoitus kertoa Keskity olennaiseen, älä läiski kuvaan kaikkea mahdollista Esim. tavoitteena kertoa uusien komentojen lisääminen ja siihen liittyvät asiat keskity tähän & dokumentoi siihen liittyvät asiat huolella (ja jätä muut pois) Dokumentaatio, selitä kuva sanallisesti/tekstissä
tapahtumasekvenssikaaviot TIE-20200 Samuel Lahtinen
http://www.ibm.com/developerworks/rational/library/content/rationaledge/feb04/3101_figure10.html TIE-20200 Samuel Lahtinen
Sekvenssikaavioista Suunnitteluvaiheessa: oliot, niiden välisen vuorovaikutuksen havainnollistaminen, vastuualueiden konkretisointi ja jakaminen yms. Dokumentaatio: Havainnollistaa ohjelman ajoaikaista käytöstä, esimerkki normaalista toiminnasta, poikkeustoiminnasta jne.
Olioiden luominen Uuden olion luominen, normaalissa tilanteessa pitää tietää oikea rakentaja, oikeat parametrit, muuttuu työläämmäksi erityisesti, jos paljon eri vaihtoehtoja koodi riippuvaista toteutuksesta, jokainen uusi lisätty luokka vaatii toteutuskoodin puukottamista Ongelmaan tarjolla erilaisia ratkaisuja, rakentajametodit, rakentajaluokat, erilaiset tehtaat
Ongelma: Miten varmistaa yhdenmukaiset oliot? Alusta TAI MUTTA EI:
Abstrakti tehdas suunnittelumalli AbsFactory createproducta(): ProductA createproductb(): ProductB ProductA2 opera ProductA opera ProductA1 opera Alusta ProductB operb ProductB2 ProductB1 operb operb Factory1 <<create>> Factory2 <<create>>
Abstract Factory abstrakti tehdas Tehdasmallin idea, käyttäjälle annetaan abstrakti tehdas (tai tehdasrajapinta) jonka avulla rakentaa komponentteja Erilaisia konkreettisia tehtaita, jotka toteuttavat varsinaisen rakentamisen Rakennettavat komponentit, abstrakti kantaluokka/rajapinta ja konkreettiset vastineet Tehtaan käyttäjä pyytää rakentamaan esim. uuden nappulan, tehdas Vertailu ideatasolla: olioiden kopiointi, virtuaalinen kopiointifunktio Fokus komponenttijoukon rakentamisessa
Abstract Factory abstrakti tehdas Erikoistetut tehtaat, eri ympäristöön, eri käyttöliittymään, eri käyttäjäprofiilille, jne. oma tehtaansa. Pyydetään haluttua tehdasta luomaan ohjelman käyttämät komponentit. Tehtaan käyttö samanlaista riippumatta rakennettavien olioiden tyypistä (esim. käyttöliittymäkomponenttitehdas ja eri ympäristöt, profiilit) Esimerkki: käyttöliittymäperhe ja eri ympäristöt/kirjastot Käyttöliittymätehdas rakentaa ikkunan ja sen eri osat (luox,y,z) Ikkuna kantaluokkana, erikoistetut versiot jokaiselle ympäristölle erikseen Käyttöliittymätehtaan erikoistetut versiot (vastaavat kuin komponenttien erikoistus) Mainissa tms. tarkistus, mitä versiota käytetään ja luodaan/otetaan käyttöön oikea tehdas. Muualla käytetään annettua tehdasta ja komponentteja, muu koodi toimii samoin riippumatta käytössä olevasta versiosta
Tehdasmetodi (Factory method) Editori, jonka pitäisi osata avata oikeanlainen tiedosto, eri tiedostojen avaamista ja käsittelyä varten omat tiedostolukijansa. Perinteinen tapa, jokainen eri tiedostotyyppi pitää rakentaa erikseen, if-elsejä tai vastaavia hässäköitä. Uuden tiedostotyypin lisääminen vaatii Editorin koodin puukottelua. Sama tapahtuu tiedoston muuntamisessa muodosta toiseen Olisi huomattavasti mukavampaa, jos saman voisi tehdä automaattisesti ja uusien tyyppien lisääminen ei vaatisi olemassa olevan koodin käpistelyä FileConverter Editor FileReader.rtf.doc.txt.rtf.doc.txt.docx TIE-20200 Samuel Lahtinen.docx
Tehdasmetodi (Factory method) Yksinkertaisin rakentajametodi, tehdään kantaluokkaan luokkafunktio (static member function) joka hoitaa rakentamisen. Osaa päättää parametrin perusteella, mikä hierarkian olioista halutaan rakentaa Esimerkki tiedostojuttujen kanssa: Hifistelyä, jokainen aliluokka osaa rekisteröityä (automaattisesti) rakentajalle ja kertoa esim. parametrien sisällöstä (kuten tiedostotyyppi), rakentajafunktio/olio kutsuu parametrin perusteella oikeaa rakennusmetodia ja uusi oikeantyyppinen oli syntyy Funktion käyttäjän ei tarvitse tietää mitään toteutuksesta tai luokkahierarkiasta FileConverter Editor FileReader.rtf.doc.txt.rtf.doc.txt.docx TIE-20200 Samuel Lahtinen.docx
Rakennuttajien automaattisesta rekisteröinnistä Automaattisesti tehtaalle/rakennuttajalle rekisteröityvien luokkien tekeminen Uusi luokka vaatii vain käännöksen ja kaikki toimii kivasti toteutustapoja luokkamuuttujat, luokkafunktiot static-muuttujat, joiden arvo alustetaan rekisteröintifunktion avulla Template-hässäkät C++11 ja lambdat Ongelmia: Kääntäjät turhan innokkaita optimoimaan ja saattavat jättää esim. muuttujien alustuksen tekemättä ennen kuin niitä käytetään ensimmäistä kertaa Lisää kompleksisuutta
Object Pool (olioiden kierrättämistä) Olioiden luominen ja tuhoaminen voi olla raskasta erityisesti jos niihin liittyy vähänkään monimutkaisempia alustustoimenpiteitä Uusien luomisen sijaan tarjotaankin olioita käytettäväksi olioaltaasta Kun tarve tulee, olioaltaasta voi noutaa olion ja käytön jälkeen palauttaa sen takaisin (kuten keilahalli ja keilakengät) Voidaan kontrolloida käytössä olevien olioiden määrää, saadaan kapseloitua olioiden luominen Käyttäjä ei huomaa eroa, kutsuna pyydetään olioita ja tuloksena voi olla joko uusi olio tai jo jonkun aikaisemmin palauttama Suorituskyvyn optimointi tai tarve kontrolloida olioiden määrää
Koodiesimerkki (olioallas C#) TIE-20200 Samuel Lahtinen
Resource Acquisition is Initialization (RAII) Programming idiom (C++), ei siis suunnittelu/toteutusmalli (yleistettävyys) Idea: resurssin vapauttamisesta huolehtii purkaja (ja varaamisesta rakentaja) Resurssin varaus näkyvyysalueen mukaan, automaattinen vapauttaminen, ei muistamisongelmaa/poikkeustilanneongelmaa jne. Tiedostojen, kuvaresurssien, mutexien yms. vastaavien asioiden käyttö kääritään varaaminen rakentajaan ja vapauttaminen purkajaan. Käytetään käärijää(wrapper) vain staattisesti, ei dynaamisen muistinvarauksen kanssa automaattinen vapautus kun näkyvyysalue päättyy
Poikkeusturvallisuus ja RAII Poikkeusturvallisuus ja C++:n sudenkuopat Esimerkkejä potentiaalisista ei-turvallisista toimenpiteistä File initfile; initfile.open( "init.txt" ); // potentiaalinen riski, poikkeus täällä ja tiedostoa ei suljeta missään initializestufffromfile( f ); initfile.close(); Resource* resource = new Resource( ); // turvatonta, jos tulee poikkeus, delete jää kutsumatta useresourceinotherplace( resource ); delete resource; Lock* lock = getlock(); lock.aquire(); // jos tulee poikkeus, lukitus jää vapauttamatta (ja ohjelma todennäköisesti jämähtää) dosomething(); lock.release();
Mutex-esimerkki td::mutex mymutex; void huonoesimerkki() { mymutex.lock(); dostuff(); // Huono juttu, jos dostuff voi heittää poikkeuksia, jää mutex // vapauttamatta ja ohjelma todennäköisesti lukkoon (deadlock) mymutex.unlock(); } void parempiesimerkki() { std::lock_guard lk( mymutex ); // RAII-mallin mukainen std::lock_guard (lukitsee // rakentajassa mutexin) dostuff(); } // <- lock_guard:in purkaja vapauttaa mutexin
Yhteenveto Olioiden luomiseen liittyvät mallit/patternit, helpottavat laajennettavuutta, vähentävät suoria toteutusriippuvuuksia Lisäävät koodin määrää, tekevät ohjelmasta hieman monimutkaisemman Usein erittäin hyödyllisiä ohjelman muokattavuuden ja laajennettavuuden säilyttämiseksi TIE-20200 Samuel Lahtinen 21
Kirjastot Yleiskäyttöinen, valmis koodi jaetaan yleensä valmiiksi käännettynä Ei tarvetta muuttaa, ei tarvetta nähdä lähdekoodia, säästetään aikaa käännösvaiheessa jne. Valmiin koodin levittäminen isona kasana objektitiedostoja vähemmän kätevää Fiksumpaa yhdistää kaikki objektitiedostot kirjastoksi, joka linkitetään mukaan ohjelmaan Käyttöön tarvitaan otsikkotiedosto (include) ja kirjasto (jossa käännetty koodi)
Kirjastotyyppejä Käännösaikaiset kirjastot Kirjastosta käytössä olevat osat linkitetään osaksi ajettavaa ohjelmaa Kirjaston konekoodi mukana jokaisessa ohjelmatiedostossa (vie tilaa) Uusi versio kirjastosta vaatii uudelleen linkkaamisen jotta ohjelmisto pystyy käyttämään sitä Ajonaikaiset kirjastot (dll, shared libraries) Linkatessa kirjataan, mitä kirjastoa tarvitaan Käynnistyksen yhteydessä tarvitut kirjastot ladataan Kirjastojen täytyy löytyä jostain (ja olla rajapinnoiltaan samaa versiota kuin niiden käyttäjät)
Jaetut/dynaamiset kirjastot Natiivisti käännettävät kielet (esim. C++) Vaativat käyttöjärjestelmä/ympäristökohtaisten kirjastojen/palveluiden käyttöä ajoaikaiseen yhdistämiseen Ei osa kieltä Tulkattavat kielet, virtuaalikoneympäristöt, yms. ajoympäristöt (esim..net) Tulkattavat kielet, tulkki ajaa ohjelmaa, joten kirjastokoodit jne. uusimman version mukaan (esim. Javascript), viitataan koodiin ja tiedostoihin, ei kirjastoihin. Kirjaston ero tavalliseen kehityksessä olevaan koodin lähinnä koodin tiiveys Java, C#... oma ajoympäristö tarjoaa keinoja pakettien ja kirjastokomponenttien hallintaan. Ei vaadi erillisten käyttöjärjestelmäkirjastojen käyttöä TIE-20200 Samuel Lahtinen
Liitännäisohjelman rakenteesta Pääohjelma itsenäinen kokonaisuus, voi toimia ilman liitännäisiä (liitännäiset voivat olla ladattavissa myös ajoaikaisesti) Pääohjelma tarjoaa liitännäisille: Rekisteröintipalveluita Rajapinnan, jonka liitännäinen toteuttaa Yleensä Mahdollisuuden resurssien/tiedon vaihtoon (pääohjelma liitännäinen) Joko pääohjelma tarjoaa niitä kutsuessaan liitännäisen palveluita tai pääohjelma paljastaa rajapintoja, joista palveluihin pääsee käsiksi (API) Liitännäinen toteuttaa annetun rajapinnan, tarjoaa pääohjelmalle rajapinnan mukaisia palveluita (usein tee toiminto-henkisiä) TIE-20200 Samuel Lahtinen 25
Rakenne Liitännäisen rajapinta Liitännäisten hallitsija liitännäinen Tarjotut palvelut Ohjelman liitännäiselle tarjoama(t) rajapinta (rajapinnat) TIE-20200 Samuel Lahtinen 26
Kysymyksiä: plussaa/miinusta Mitä hyvää/huonoa staattisissa, dynaamisissa tai pluginratkaisuissa? Mitä vaatimuksia kukin asettaa (ohjelman suunnittelun kannalta)? Milloin käyttäisit mitäkin lähestymistapaa? Kohdekäyttäjät: viihde, työ, teollisuus, julkinen/yritysten sisäiseen käyttöön Ennustetut päivitystarpeet (jatkuvat päivitykset, monia toimittajia, harvat päivitykset/asennus firman toimesta) Asentaminen, ilman asennusohjelmaa/asennusohjelman kera Ohjelman koko (iso vs. pieni)
vastauksia Staattisesti linkitettävät +yksinkertainen, saman ympäristön sisällä siirrettävä +helppo asentaa, käyttää, kaikki samassa -vie enemmän tilaa/muistia (jos ohjelmasta useita instansseja ajossa/jos samaa kirjastoa käyttäviä ohjelmia paljon, -päivittäminen == koko köntin vaihtaminen, jos ohjelman koko kasvaa, huono ratkaisu Dynaamisesti linkitettävät +jaettu kirjasto, tilankäyttö vähenee, voidaan päivittää koskematta sitä käyttäviin ohjelmiin, voidaan päivittää ohjelmaa osa kerrallaan -eri versiot kirjastoista, keskinäinen yhteensopivuus, riippuvuuspolut, samalla koneella voi olla useampia versioita samasta kirjastokomponentista, koko paketista huolehtiminen (vaatii yleensä asennusohjelmia, erillisiä päivitysohjelmia)
vastauksia Plugin-ratkaisut +mahdollista latailla ajoaikaisestikin, vaihtaa, laajentaa, lisätä +voidaan tarjota käyttäjäyhteisölle/muille firmoille mahdollisuus laajentaa omaa ohjelmistoa, uutta toiminnallisuutta jne. ilmaiseksi -laajennettavuuden suunnittelu ja toteutus vievät aikaa/resursseja -laajennusrajapinnat suunniteltava huolella (turvallisuus, toimivuus) -liitännäiset saattavat rikkoa/kaataa hyvin toimivan pääohjelmankin -jos muut saavat tehdä laajennuksia, kuka tekee laadunvarmistuksen/turvallisuusvarmistukset?
Ajoaikaiset kirjastot Mitä voidaan muuttaa ilman että kirjastoa käyttävää ohjelmaa tarvitsee päivittää? Toteutus: kunhan noudatetaan sopimussuunnittelun mukaisesti jälki- ja esiehtoja Rajapinta: Yleisohje, ei saa muuttaa Tarkemmin: Uusien ei-virtuaalisten funktioiden lisääminen mahdollista Vanhojen funktioiden muuttaminen, uusien virtuaalifunktioiden lisääminen myös kirjaston käyttäjät pitää kääntää uudelleen
Jaetut/dynaamiset kirjastot Ja asennukset Asennus tärkeää, minne kirjastokomponentit tulevat, että ohjelmat löytävät ne? vaihtoehtoja: Käyttöjärjestelmän hakemistoihin Ohjelman ajohakemiston alihakemistoon Erilliseen kirjastohakemistoon Mitä mukaan? C++, itse dll ja otsikkotiedostot, jos halutaan tukea muita kehittäjiä? Myös kehitystyökalun kirjastot Esim Qt:n kanssa http://qt-project.org/doc/qt-5.0/qtdoc/deployment-windows.html Yleensä asennusohjelma tarpeen/hyödyllinen
Qt ja kirjastokomponentit Qt tarjoaa mahdollisuuden luoda kirjastokomponentteja ja dynaamisesti ladattavia ohjelman osia Hyödyntää käyttöjärjestelmien päälle tehtyjä palveluita (oma sovitus, Linux, Windows, Mac versioille) Mahdollisuus laajentaa Qt:ta tai omaa sovellusta
Qt ja kirjastokomponentit Jotain linkkejä: http://gertverdemme.nl/dev/cpp/qt/build_shared_libraries http://qt-project.org/doc/qt-5.0/qtwidgets/toolsplugandpaint.html http://qt-project.org/doc/qt-5/plugins-howto.html http://qt-project.org/doc/qt-5/qpluginloader.html
Yhteenveto Opittiin erilaisia tapoja huolehtia olioiden luomisesta ja elinajasta. Ongelma/tarve kertoo, minkätyyppinen ratkaisu olisi toimiva. Opittiin C++-koodarin hyvä ystävä RAII (tämä ei roskienkeruujärjestelmässä toimikkaan näin kivasti) Opittiin peruskäsitteistöä kirjastoista ja plugineista. Jatkossa myös jotain toteutustavoista jne.