Ohjelmoinnissa , erityisesti olio-ohjelmoinnissa , luokkainvariantti ( tai tyyppiinvariantti ) on invariantti , jota käytetään rajoittamaan luokan objekteja. Luokkamenetelmien tulee säilyttää invariantti.
Luokkien luomisen aikana muodostetaan niiden invariantteja, joita ylläpidetään jatkuvasti julkisten menetelmien kutsujen välillä. Tilapäinen luokan invarianssin rikkominen yksityisten menetelmäkutsujen välillä on mahdollista, vaikkakaan ei toivottavaa.
Olioinvariantti on ohjelmointirakennelma, joka koostuu joukosta muuttumattomia ominaisuuksia. Tämä varmistaa, että objekti vastaa aina ennalta määritettyjä ehtoja, ja siten menetelmät voivat aina viitata objektiin ilman riskiä tehdä epätarkkoja olettamuksia. Luokkainvarianttien määrittäminen voi auttaa ohjelmoijia ja testaajia löytämään enemmän virheitä ohjelmiston testauksen aikana.
Luokkainvarianttien hyödyllistä vaikutusta olio-ohjelmoinnissa tehostaa periytymisen läsnäolo. Luokkainvariantit ovat periytyviä, eli luokan kaikkien vanhempien invariantit koskevat itse luokkaa. [yksi]
Periytys sallii jälkeläisluokkien muuttaa yläluokkien toteutustietoja, joten jälkeläinen luokka voi muuttaa ilmentymien tilaa tavalla, joka tekee niistä kelpaamattomia yläluokan näkökulmasta. Viittaus tähän virheelliseen lapsityyppiin on yksi syistä, miksi oliopohjaiset ohjelmistokehittäjät suosivat kapselointia perinnön sijaan. [2]
Koska luokkainvariantit kuitenkin periytyvät, minkä tahansa tietyn luokan luokkainvariantti koostuu kaikista suoraan kyseiseen luokkaan koodatuista invarianteista lauseista yhdistettynä kaikkiin kyseisen luokan vanhemmilta perittyihin invarianteihin. Tämä tarkoittaa, että vaikka jälkeläiset luokat voivat käyttää vanhempiensa toteutustietoja, luokkainvariantti voi estää niitä käsittelemästä tietoja millään tavalla, joka luo virheellisen ilmentymän ajon aikana.
Ohjelmointikielet, kuten C++ ja Java , tukevat oletusvahvistuksia , joita voidaan käyttää luokkainvarianttien määrittämiseen. Yleinen esimerkki invarianttien toteutuksesta luokissa on, että luokan rakentaja heittää poikkeuksen, jos invarianttia ei täyty. Koska menetelmät säilyttävät invariantteja, ne voivat hyväksyä invariantin pätevyyden, eikä niitä tarvitse erikseen tarkistaa.
Luokkainvariantti on sopimusohjelmoinnin olennainen osa . Siten ohjelmointikielet, jotka tarjoavat täyden tuen sopimusohjelmointia varten, kuten Eiffel , Ada ja D , tarjoavat myös täyden tuen luokkainvarianteille.
Javassa on tehokkaampi työkalu nimeltä Java Modeling Language , joka tarjoaa tehokkaamman tavan määrittää luokkainvariantteja.
D-ohjelmointikielessä on sisäänrakennettu tuki luokkainvarianteille sekä muille sopimusohjelmointitekniikoille. Tässä on esimerkki virallisesta dokumentaatiosta.
class Päivämäärä { int päivä ; tunnin sisällä ; muuttumaton () { assert ( 1 <= päivä && päivä <= 31 ); assert ( 0 <= tunti && tunti < 24 ); } } EiffelEiffelissä luokkainvariantti ilmoitetaan luokan lopussa avainsanan jälkeen.
luokka DATE luoda merkki ominaisuus { EI MITÄÄN } -- alustus make ( a_day : INTEGER ; a_hour : INTEGER ) -- Alusta "Nykyinen" arvoilla "a_day" ja "a_hour". vaadi voimassa_päivä : 1 <= a_päivä ja a_päivä <= 31 kelvollinen_tunti : 0 <= a_tunti ja a_tunti <= 23 do day := a_day tunti := a_hour varmista day_set : day = a_day hour_set : hour = a_hour end ominaisuus -- Pääsy päivä : INTEGER -- kuukauden päivä arvolle "Nykyinen" tunti : INTEGER -- vuorokauden tunti arvolle "Nykyinen" ominaisuus -- Elementin muutos set_day ( a_day : INTEGER ) -- Aseta `day' arvoon 'a_day' vaativat valid_argument : 1 <= a_day ja a_day <= 31 do day := a_day varmista day_set : day = a_day end set_hour ( a_hour : INTEGER ) -- Aseta `tunti' arvoon `a_hour' vaatii valid_argument : 0 <= a_tunti ja a_tunti <= 23 do tunti := a_hour varmista tunnin_setti : tunti = a_tunti loppu muuttumaton voimassa_päivä : 1 <= päivä ja päivä <= 31 kelvollinen_tunti : 0 <= tunti ja tunti <= 23 loppuTämä on esimerkki luokkainvariantista Java-ohjelmointikielessä Java-mallinnuskielen kanssa. Invariantin on oltava tosi sen jälkeen, kun konstruktori on valmis, sekä kaikkien julkisen funktion jäsenten tullessa sisään ja poistuttaessa. Tämän on määriteltävä ennakko- ja jälkiehto luokkainvariantin pakottamiseksi.
julkinen luokka Päivämäärä { int /*@spec_public@*/ päivä ; int /*@spec_public@*/ tunti ; /*@invariantti 1 <= päivä && päivä <= 31; @*/ //luokkainvariantti /*@invariantti 0 <= tunti && tunti < 24; @*/ //luokkainvariantti /*@ @vaatii 1 <= d && d <= 31; @vaatii 0 <= h && h < 24; @*/ julkinen Päivämäärä ( int d , int h ) { // rakentajan päivä = d ; tunti = h ; } /*@ @vaatii 1 <= d && d <= 31; @varmistaa päivän == d; @*/ public void setDay ( int d ) { päivä = d ; } /*@ @vaatii 0 <= h && h < 24; @varmistaa tunnin == h; @*/ public void setHour ( int h ) { tunti = h ; } }