Johdanto olio-ohjelmointiin

Olio-ohjelmoinnin perusta

Luokka

1. Jo muinaiset room.. eikun kreikkalaiset pohtivat olioiden ideaa
2. Platonin mielestä olentojen idea (luokka) oli yksittäistä olentoa tärkeämpi (olio) http://tarmo.fi/blog/2003/09/platonin-oliot/
3."Sen sijaan, että joudumma sanomaan “Tuo tuossa on nelijalkainen ihmisen korkuinen karvainen kavioeläin, jolla voi ratsastaa”, voimme sanoa “Tuo tuossa on hevonen.” Tehokkaampaa." :)
4. Ihminen luokittelee asioita, koska: aivojen työmuistiin mahtuu kerrallaan vain 4-7 asiaa. Luokittelemalla on mahdollista hanskata isompia ja vaikeampia kokonaisuuksia
5. Ihminen luokittelee kaikkea, eläimiä, kasveja, autoja, tietokoneita,...
6. miksei myös tietokoneohjelmassa tarvittavia asioita
=> Luokittelu helpottaa ihmisen ajattelua kaikilla tasoilla, myös ohjelmoinnissa

Luokkien keksiminen ohjelmoinnissa

1.Auttaa asioiden hahmottamisessa -> Ongelmasta osaongelmiin
2.Hyvien luokkien keksiminen erittäin haastava työ
3.Useita välineitä ja menetelmiä luokkien graafiseen kuvaamiseen
4.Itse luokkajaot on kuitenkin loppupelissä keksittävä itse

Olio

1.Olio on luokan ilmentymä (edustaja, instanssi, ...)
2.Esimerkiksi Musti (tietty olio) on koirien (luokka) edustaja
3.Saman luokan edustajilla eli olioilla samanlainen rakenne (neljä jalkaa, kuono, ...), mutta ominaisuudet erilaisia (jalkojen pituus).
4.Saman luokan edustajilla eli olioilla samat toiminnot: hengittää, haukkuu, juoksee, ...

Yleistä

Olio-ohjelmointi on yksi eri ohjelmointiparadigmoista (paradigma on ajattelumalli). Ohjelmoinnissa eri paradigmojen tarvoite on kuvata järjestelmien rakennetta ja toimintaa. Olio-ohjelmoinnin keskeisenä tavoitteena on toteuttaa ohjelmointia siten, että saavutetaan mahdollisimman hyvä ohjelmoinnin uudelleenkäytettävyys. Kertaalleen kirjoitettua koodia ei kirjoiteta uudelleen. Oliopohjainen koodi kirjoitetaan ja kootaan pienistä helposti hahmotettavista ohjelman osista, joiden toiminnallisuus määritellään erittäin tarkasti. Järkevästi suunniteltu ja jaoteltu ohjelmointi on helposti hallittavissa. Näin ollen hyvin toteutetusta ohjelmoinnista tulee automaattisesti myös helposti ylläpidettävää, koska tiettyyn kohtaan tehdyt muutokset eivät pääse vaikuttamaan sovelluksen joka puolelle.

C#:n primitiivityypit (int, double, bool, jne..) antavat melko rajoittuneet mahdollisuudet toteuttaa laajempia ohjelmakokonaisuuksia, koska niillä pysytytään tallentamaan ainoastaan lukuja ja yksittäisiä kirjaimia. Onneksemme C# on oliopohjainen ohjelmointikieli ja se tarjoaa näin ollen huikeat puitteet erimuotoisten tietojen käsittelyyn oliorakenteiden avulla.

Siirtyminen oliomaisempaan ajatteluun

Perinteiset proseduraaliset lausekieliset ohjelmat toteutetaan peräkkäisillä käskyillä. Tällainen lausekielinen ongelmien ratkaisutapa on suoraviivainen ja soveltuu pienehköihin tehtäviin. Tämän päivän tietokoneiden käyttöliittymät ja ohjelmistot ovat kuitenkin kehittyneet valtaviksi kokonaisuuksiksi ja on tarvittu uusia tehokkaampia keinoja toteuttaa monimutkaisempia asioita.

Pohditaan yhdessä esimerkiksi pankkiautomaatin toimintasuunnitelmaa lausekielellä:


    1. Odota korttia
    2. Jos kortti annettiin, kysy tunnusluku
    3. Jos tunnusluku on oikein siirry rahan nostamiseen
    3.1 Jos tunnusluku on väärin palaa kohtaan 2
    3.2 Jos tunnusluku syötettiin väärin kolmannen kerran, ota kortti talteen. Palaa kohtaan 1.
    4. Kysy nostettava summa
    5. Jos tilillä on euroja riittävästi: anna rahat ja siirry kortin palautuskohtaan
    5.1. Jos tilillä ei ole riittävästi katetta: palauta kortti tai siirry kohtaan 4.
    6. Palauta kortti
    7. Palaa kohtaan 1.
    

Yllä olevan ohjelman toteuttaminen pelkästään "tee sitä ja sitten tätä" -tyylisellä proseduraalisella ohjelmoinnilla alkaa muodostua kohtalaisen hankalaksi. Siirtyminen oliomaisempaan ajatteluun - Apua olioista?

Pankkiautomaatti voidaan myös kuvata oliomaisena:


    itse automaatti on olio (tosin voidaan ajatella myös pienempinä olioina!)
    kortin vastaanottolaitteisto - huolehtii kortin otosta ja palautuksesta
    näppäimistö - huolehtii käyttäjän valinnoista
    rahan säilytyslaitteisto - huolehtii rahan säilytyksestä
    rahan antolaitteisto - huolehtii rahojen jakelusta
    verkkolaitteisto - huolehtii yhteyksistä keskuspankkiin (tunnusluvut, saldot, yms)
    näyttölaitteisto - huolehtii viesteistä käyttäjälle
    jne...
    

Jokainen yllä mainituista pankkiautomaatin itsenäisistä osista eli olioista on tietyssä tilassa. Esimerkiksi kortinvastaanottolaitteen on tiedettävä onko käyttäjä syöttänyt kortin vai ei. Jos kortti on annettu, välittää kortinvastaanottolaitteisto viestin näytölle (kertoo käyttäjälle, että tunnusluku on syötettävä) ja näppäimistölle (ottaa vastaa kortin tunnusluvun). Rahan antolaitteistolla voisi olla AnnaRahat-toiminto, jota käytetään ainoastaan rahanantolaitteisto-oliossa.

Tärkeää on ymmärtää asioita yksittäisinä kokonaisuuksina eli olioina.

Peruskäsitteitä

Olio (object)

Olio-ohjelmoinnissa olio kuvaa yleensä jotain reaalimaailman käsitettä. Olion tärkein tehtävä on sisältää sen siihen koskevat tiedot sekä tietoihin kohdistuvat toiminnot. Olio-ohjelmoinnin periaatteiden mukaisesti olion tulee suojata omat tietonsa siten, että niihin pääsee käsiksi vain sen toimintojen kautta. Aika useasti ohjelmoijat lipsuvat tässä ja päästävät olion tilaa muuttamaan suoraan myös sen ominaisuuksien kautta. On osin ohjelmoijan valinta miten hän toteuttaa luokan ominaisuuksien muuttamisen. Pääperiaatteena voi olla että ominaisuuksia voi muuttaa joko pelkästään metodien kautta tai ominaisuuksien kautta. Ei voi sanoa että toine on toista parempi vaihtoehto, mutta päässääntöisesti kannattaa valita vain toinen tapa ja noudattaa sitä. (ES: ominaisuuksia muutetaan vain ominaisuksien kautta PM: tällä opintojaksolla pyritään noudattelemaan olio-ohjelmointia siten, että olion ominaisuuksia muutetaan vain sen toimintojen kautta).

Olion tila muodostuu siis sen kaikista ominaisuuksista. Olion tilaa eli ominaisuuksia muuttavat sen toiminnot. Toim.Huom. Olion tilaa muuttaa myös sen ominaisuuden muutos, ja sen täytyy kapselointi periaatteen vuoksi tapahtua aina hallitusti!

Esimerkki: Opiskelija-olio, versio A

* ominaisuuksia: Etunimi, Sukunimi, Ryhmä, Sotu, Ikä, Osoite, ....
* toimintoja: MuutaEtunimi, KerroEtunimi, Vanhene, LiitäOpintojaksolle, ...

Esimerkki: Opiskelija-olio, versio B

* ominaisuuksia: Etunimi, Sukunimi, Kokonimi, Ryhmä, Sotu, Syntymäaika, Ikä, Osoite, ....
* joista ominaisuuksia joita voi vain lukea mutta ei asettaa (read-only): Kokonimi, Ikä * toimintoja: tässä tapauksessa vältetään toimintoja joista tulisi englannin kielellä Get-jotain tai Set-jotain, eli versiosta A jäisi jäljelle LiitäOpintojaksolle. Metodeja KerroEtunimi, AsetaEtunimi ei tarvita koska ominaisuuksien muutokset hoidetaan asettamalla ominaisuus (property).

Esimerkki: Auto-olio

* ominaisuuksia: Merkki, Malli, Väri, Nopeus, Paino, Teho, ....
* toimintoja: NäytäTiedot, Kiihdytä, Jarruta, NäytäNopeus, ...

Olion toiminnallisia osia kutsutaan metodeiksi:
* metodien voidaan ajatella vastaavan tavallisen lausekielisen ohjelmoinnin aliohjelmia eli funktioita
* metodit on kiinnitetty aina johonkin olioon (tai luokkaan)

Luokka (class)

Olion luominen pohjautuu aina johonkin luokkaan. Luokka määrittelee olion ominaisuudet ja toiminnot. Olio on luodun luokan ilmentymä eli instanssi. Luokka on siis tavallaan olion pohjapiirrustus. Olio on tästä pohjapiirrustuksesta luotu todellinen ilmentymä.

Esimerkkejä:

* piparkakkumuotti on luokka, jolla voidaan tehdä piparkakkuja (oliota)
* Auto on luokka ja esimerkiksi silloin Ford Fiesta voisi olla olio Auto-luokasta
* Kissa on luokka ja esimerkiksi silloin Mirri on olio
* Kirja on luokka ja esimerkiksi silloin voisi olla Aapinen olio Kirja-luokasta

Oliot vs reaalimaailma

Olio-paradigman yksi tarkoitus on että luokat ja oliot paremmin vastaavat reaalimaailman asioita. Luokka (class) edustaa jotain asiaa tai käsitettä yleensä ja olio (object) on ilmentymä luokasta. Olio edustaa jotain joka voidaan yksilöidä samanlaisista olioista. Olio on siis aina "yksilö", jolloin oliolla on siis identiteetti.


namespace JAMK.IT
{
  public class Koira
  {
    //Properties
    public string Nimi { get; set; }
    public Color Väri { get; }
    //Constructors
    public Koira()
    {
      this.Väri = Color.Black;
    }
    public Koira(string nimi) : base()
    {
      this.Nimi = nimi;
    }
    //Methods
    public string Murisee()
    {
      //some interesting growling action happens here...
      return "Murrr";
    }
    public string Haukkua(int kertaa)
    {
      //some interesting barking action here...
      string bark = "";
      for (int i = 0; i < kertaa; i++)
      {
        bark += " vuh ";
      }
      return bark;
    }

  }
  class KoiraDemo
  {
    static void Main(string[] args)
    {
      TestaaKoira();
    }

    static void TestaaKoira()
    {
      //Yksinkertainen esimerkki, meillä on luotuna luokka Koira
      //luodaan uusi olio eli "ilmentymä"
      Koira munKoira = new Koira();
      //koiralla voi olla erilaisia ominaisuuksia (property),
      //ominaisuudet voivat olla joko luettavissa ja asetettavissa tai pelkästään luettavissa (read-only)
      munKoira.Nimi = "Sesse";
      Color väri = munKoira.Väri;
      //kokoelma samanlaisia olioita, reaalielämässä siis esim. koiralauma
      Koira sunKoira = new Koira("Jekku"); 
      List<Koira> koirat = new List<Koira&g;();
      koirat.Add(munKoira);
      koirat.Add(sunKoira);
      //viittaaminen yksittäiseen koiralauman koiraan (eli olioon) indeksillä
      Koira laumanPomo = koirat[0];
      //olioilla voi olla myös menetelmiä (method)
      Console.WriteLine("Minun koirani {0} sanoo {1}", munKoira.Nimi, munKoira.Murisee());
      Console.WriteLine("Sinun koirasi {0} sanoo {1}", sunKoira.Nimi, sunKoira.Haukkua(100));
      //olioilla voi olla myös tapahtuman käsittelijöitä mutta niistä myöhemmin
    }
  }
}
	

 

check_circle Olio-ohjelmointiin kuuluu lukuisia muita peruskäsitteitä, näitä käsitellään seuraavissa demoissa lisää!

Esimerkki: Auto-luokka ja auto-oliot

Pohdintaan yhdessä tarkemmin Auto-luokkaa ja siitä luotavia auto-olioita. Auto-luokan edustajia eli oliota voisivat olla esimerkiksi Datsun, Porsche ja Toyota. Näillä voisi olla esimerkiksi seuraavat ominaisuudet:

  • Datsun

  • Merkki: Datsun 100A
  • Väri: punainen
  • Moottori: 1.0
  • Nopeus: 120
  • Karvanopat: on
  • Ovimäärä: 2
  • Porsche

  • Merkki: Porsche 911
  • Väri: keltainen
  • Moottori: 5.5
  • Nopeus: 200
  • Karvanopat: ei
  • Ovimäärä: 2
  • Toyota

  • Merkki: Toyota Corolla
  • Väri: harmaa
  • Moottori: 1.5
  • Nopeus: 180
  • Karvanopat: ei
  • Ovimäärä: 4

Yllä olevasta taulukosta voidaan selkeästi jo alkaa nähdä millainen pohjapiirustus Auto-luokalla voisi olla. Luokkien ja olioiden yhteydessä puhutaan ns. UML-mallinnuksesta, jonka yksi osa-alue on mm. luokkakaavioiden suunnittelu. Tähän käsitteeseen palataan opintojaksolla vielä myöhemmin.

Auto-luokka UML-luokkakaaviona: kaaviossa on ylhäällä näkyvissä luokan nimi, keskellä ominaisuudet ja alhaalla toiminnot.

Luokan sisältö

Yleisesti

Olio-ohjelmoinnissa luokan sisälle määritellään ensin luokan käyttämät jäsenmuuttujat ja ominaisuudet. Tämän jälkeen määritellään mahdolliset luokan alustajat eli konstruktorit, joiden avulla itse olio luodaan. Viimeisimmäksi tulevat luokan toteuttamat metodit eli toiminnot, indeksoijat ja mahdollinen olion tuhoaja eli destruktori. Tämä ei ole mikään kiveen kirjattu sääntö, mutta aika useiden olio-ohjelmointikielien kohdalla hyväksi todettu menettely.


    class ClassName
    {
        // field variables
        // properties
        // constructors
        // methods
        // events
        // indexer
        // destructor
    }
    

Jäsenmuuttujat (field)

Luokan jäsenmuuttujina määritellään muuttujat, jotka ovat käytössä vain luokan sisällä (nimet aloitetaan pienellä kirjaimella, huomaa myös että jäsenmuuttujien nimen alussa ei käytetä alaviivaa niinkuin joissakin muissa kielissä). Luokan jäsenmuuttuja voi olla myös luokkakohtainen, jolloin sen esittelyssä on käytetty static-avainsanaa (tällöin muuttuja on yhteinen kaikkien sen instanssien kesken). Jäsenmuuttujia voidaan käyttää luokan sisällä tarvittavien toteutuksien laadinnassa tai sitten niissä voi olla tietoa, jota muutetaan luokan ominaisuuksien kautta.


    class ClassName
    {
        // field
        private string model;
        private string color;
        private static string some;
        
        // property
		//ominaisuuden arvon voi sekä lukea että asettaa
        public string Model {
            get { return model; }
            set { model = value; }  //value -sana on kieleen sisäänrakennettu 
        }
        ...
    

Jäsenmuuttujalle voidaan määritellä myös pelkästään get , jolloin se on ainoastaan luettavissa oleva arvo eikä sen arvoa pysty muuttamaan/asettamaan eli niin sanotusti "read-only".


    public class Person
    {
        // fields
        private string firstname;
        private string lastname;
        
        // property
		//ominaisuus jonka arvon voi vain lukea 
        public string Name {
            get { return firstname + " " + lastname; }
        }
        ...
    

Esimerkki Henkilö-luokasta


	public class Henkilo
{
    // ominaisuus
    public char Sukupuoli
    {
        get
        {
            // palauttaa kentän arvon
            return sukupuoli;
        }
        set
        {
            // asettaa arvon kenttään
            sukupuoli = value;
        }
    }
    // yksityinen kenttä
    private char sukupuoli;
 
    // "vain luku"-ominaisuus Nimi
    public string Nimi
    {
        get
        {
            // palauttaa koko nimen
            return etunimi + " " + sukunimi;
        }
    }
    // kaksi yksityistä kenttää
    private string etunimi;
    private string sukunimi;
}

Jäsenmuuttujien arvo voi olla myös ns. "readonly"-tilassa, eli sille voidaan asettaa arvo vain kerran määrittelylauseen tai konstruktorin yhteydessä.


    public class Spaceship
    {
        private readonly int speed = 10;
        private readonly int velocity;
        
        // in constructor
        public Spaceship(int velo) {
            velocity = velo;
        }
    

Jäsenmuuttujien yhteydessä voidaan käyttää myös const-avainsanaa, muuttuja on siis varsinaisesti vakio eli tällöin jäsenmuuttujan arvo voidaan määritellä vain sen esittelyn yhteydessä.


    class Program
    {
        private const int maxSpeed = 300;
    

check_circleHyvään ohjelmointitapaan kuuluu että muuttujat muuttuvat ja vakiot pysyvät vakioina, eikä toistepäin niin kuin joskus tuppaa käymään ;-)

Ominaisuudet

Luokan ominaisuuksina kuvataan kaikki ne asiat mitä arvoja olio voi sisältää ja tarjoaa olion ominaisuuksina käyttöön toisille luokille. Tässä vaiheessa ominaisuudet pidetään vielä täysin julkisina (public). Olion tilaa suojaaviin suojamääreisiin tutustutaan myöhemmissä demoissa. Ominaisuudet näyttävät luokan ulkopuolelle jäsenmuuttujilta, mutta todellisuudessa niitä voidaan käsitellä luokan sisällä kuten toimintoja eli metodeja (huomaa get- ja set-määrittelyt).

check_circleC#:ssa on käytössä niin sanottu Auto-Implemented Properties. Tällöin propertyn määritteleminen on nopeaa ja helppoa. Auto-Implemented propertyn taustalla käytetään sisäistä piilotettua muuttujaa, johon ei pääse käsiksi eikä tarvikaan päästä.
Auto-luokan tapauksessa ominaisuudet olisivat seuraavaa muotoa:


    public class Car
    {
        // public properties
        public string Model { get; set; }
        public string Color { get; set; }
        public int Speed { get; set; }
        ...
    

Olio-ohjelmoinnissa julkisia kenttiä (kuten yllä on kuvattu) pidetään huonona ratkaisuna. Esimerkiksi yllä olevassa voitaisiin auton julkiseen Speed-ominaisuuteen asettaa mikä tahansa arvo, vaikkapa negatiivinenkin, eikä sitä rajoittaisi mikään.

Luokan ominaisuuksien avulla yhdistetään luokan jäsenmuuttujien (kentän) ilmaisuvoima sekä toimintojen turvallisuus. Tällöin ominaisuudet määritellään kuten aikaisemmen esitetyt jäsenmuuttujat ja ominaisuuden sen arvon muutosta/palatusta säädellään ns. aksessoreilla. Tähän palataan myöhemmissä demoissa.

Alla on kuitenkin näkyvissä jo pienimuotoinen teaseri tulevasta. Get-aksessori palauttaa auton nopeuden ja set-aksessori rajaa autoon sijoitettavaa speed-arvoa.


    class Car
    {
        private int speed;
        public int Speed {
            get { return speed; }
            set { 
                if (value >= 0 && value <= 200) { speed = value; } 
                else speed = 0;
            }
        }
        ...
    

Konstruktorit eli luokan alustajat

Ominaisuuksien jälkeen esitellään luokan käyttämät alustajat eli konstruktorit, joiden avulla luokasta voidaan luoda olioita. Konstruktoreiden avulla oliot voidaan alustaa haluttuun tilaan sen saamien parametrien mukaisesti. Konstruktoreita voi olla useita, ne eroavat toisistaan parametrien erojen mukaisesti. Konstuktoria ei ole pakko määritellä, tällöin käytetääm pelkästään oletuskonstruktoria, joka on määritelty kaikille luokille automaattisesti, koska luokka perii automaattisesti kantaluokan konstruktorin. Tällöin olio alustuu oletustilaan. Oletuskonstruktoria ei voida käyttää silloin kun parametrillinen konstruktori on luotu. Jos halutaan tässä tapauksessa käyttää myös oletuskonstruktoria, se täytyy konkreettisesti kirjoittaa luokan sisälle ja määritellä alustukset halutusti.

Ei konstruktoria eli käytetään oletuskonstruktoria

Tässä tapauksessa luokan sisälle ei määritellä konstruktoria ollenkaan.


    class Car
    {
        // public property
        public string Model { get; set; }
        ...

        // no constructor, default constructor will be used 
    }
    

Tällöin Car-oliota voidaan luoda kutsumalla oletuskonstruktoria seuraavasti:


    class Program
    {
        static void Main(string[] args)
        {
            // create a one car instance
            Car datsun = new Car();
            datsun.Model = "Datsun 100A";
            ...
    

Tässä tapauksessa olion ominaisuudet alustuvat oletusarvoihin : Default Values Table (C# Reference).

Käytetään parametrillista konstruktoria

Ohjelmoinnissa on tällöin päätetty, ettei oletuskonstuktori riitä, vaan jokin olion ominaisuus halutaan luokan sisällä alustaa eri tilaan, kuin mitä oletuksena eri tietotyypeille määritellään. Tämä on siis ohjelmoijan päätös luokkaa tehtäessä. Auto-luokalle voitaisiin määritellä esim. seuraavat parametrilliset konstruktorit. Tällöin puhutaan konstruktoreiden ylikuormittamisesta (overload).

Huom! Konstruktorien eroavaisuus määritellään parametrien kautta. (engl. If methods, constructors are overloaded then signatures must be unique).


    class Car
    {
        // public properties
        public string Model { get; set; }
        public string Color { get; set; }
        public bool FuzzyDices { get; set; }
        ...

        // parametric constructor, all car model will use fuzzy dices as default
        public Car() {
            FuzzyDices = true;
        } 

        // parametric constructor, model will be know when car object is created
        public Car(string model) {
            Model = model;
        }
        
        // parametric constructor, all properties will be know when car object is created
        public Car(string model, string color, bool fuzzyDices) {
            Model = model;
            Color = color;
            FuzzyDices = fuzzyDices;
        }

    }
    

Tällöin Car-oliota voidaan luoda seuraavasti:


    class Program
    {
        static void Main(string[] args)
        {
            // create a one car instance, now it has fuzzy dices as default (true)
            Car datsun = new Car();
            datsun.Model = "Datsun 100A";
            ...
            // create another car instance, model will be directly Porsche and no fuzzy dices for example...
            Car porsche = new Car("Porsche");
            porsche.Color = "yellow";
            ...
            // create another car instance
            Car porsche = new Car("Porsche","Yellow",false);
            ...
            // create one more car, using default constructor and object initializer
            Car nascar = new Car { Model = "Speedster", Engine = 2.0 };
            nascar.Color = "Yellow";
            ...
    

Toiminnallisuudet eli metodit

Luokan tulee määritellä se mitä olio osaa tehdä. Nämä toiminnallisuudet määritellään omina metodeinaan. Auto-luokan esimerkissä oli määritelty kaksi eri toimintoa: kiihdytä ja jarruta, molempien tehtävänä on muuttaa auton nopeus-ominaisuutta.


    class Car
    {
        // property
        public int Speed { get; set; }
        ...

        // method will increase car speed
        public void Accelerate() {
            Speed += 5;
        }

        // method will decrease car speed 
        public void Brake() {
            Speed -= 5;
        }
        ...            
    

Indeksoija (indexer)

Indeksoija näyttää luokan ulkopuolelta katsottuna taulukolta, mutta on todellisuudessa luokan sisällä metodi eli toiminto. Indeksoijaa käytetään silloin, kun on luontevaa käsitellä oliota indeksoidusti eli samoin kuin taulukkoa käytetään []-merkeillä. Indeksoijaksi määritellyn metodin nimi on aina this ja se saa hakasuluissa sille määritellyt parametrit. Parametrejä voi olla useita ja niiden ei tarvitse olla int-tyyppisiä. Indeksoijan toteuttamassa this-metodissa esitellään get- ja set-metodit kuten ominaisuuksien kohdalla.

Alla olevassa esimerkissä on määritelty StringCollector-luokka, joka käyttää sisäisesti taulukkoa ja indeksoijaa.


    

Luokkaa voitaisiin käyttää seuraavasti:


    
    

Destruktorit eli luokan tuhojat

Destruktorit ovat konstruktorien vastakohtia eli niitä kutsutaan kun olio halutaan tuhota. Destruktoreiden tarkoitus on vapauttaa/poistaa käyttämättömät oliot ja resurssit. C# kutsuu destruktoreita automaattisesti, ohjelmoijan ei tarvitse siitä huolehtia. Destruktorilla on sama nimi kuin luokalla, kuten konstruktorilla. Destruktorin edessä käytetään ~ etuliitettä. Destruktori on myös aina parametritön. Destruktori jätetään aika useasti kirjoittamatta, ellei mitään erityisiä resursseja olion suhteen ole vapautettavana.


    class Car
    {
        // parametric constructor, all car model will use fuzzy dices as default
        public Car() {
            FuzzyDices = true;
        } 

        // parametric constructor, model will be know when car object is created
        public Car(String newModel) {
            Model = newModel;
        }

        // destructor
        ~Car() {
            Console.WriteLine("Car object destroyed.");
        }
    }
    

Auto-luokan toteuttaminen ja käyttäminen pääohjelmasta

Car-luokka

Toteutetaan opettajan ohjeiden mukaisesti CarApplication-projekti konsoliohjelmana, joka käyttää apunaan Car-luokkaa luomaan muutamia auto-olioita.
1. Käynnistä Visual Studio 2015 ja tee uusi projekti nimelle CarApplication
2. Tee uusi luokka nimelle Car (valitse CarApplication oikealla hiiren painikkeella)
2.1 Valitse Add > Class... ja valitse Class
2.2 Anna nimeksi Car ja paina Add-painiketta
=> Nyt projekti sisältää sovelluksen pääohjelmatiedoston Program.cs ja vielä tällä hetkellä tyhjän Car.cs Car-luokkatiedoston.

Car-luokan ohjelmointi

Toteutetaan opettajan ohjeita noudatellen Auto-luokan ohjelmointi (käytetään apuna yllä määriteltyä Auto-luokan UML-kaaviota).



    

Car-luokan käyttäminen Program-luokassa

Nyt Car-luokka on käytettävissä sovelluksen Program-pääluokalle. Luodaan yksi Car-luokan olio ja tulostetaan sen tiedot näyttölaitteelle.


    

check_circle Käännä ja suorita sovellus Visual Studiosta käsin ja datsun-olion tiedot tulisi olla näkyvillä näyttölaitteella.

Toteuta pääohjelmaan myös Auto-luokan avulla porsche- ja toyota-oliot. Kokeile käyttää myös parametrillista konstruktoria Car-luokassa.

Luokan static-jäsenet

Static-avainsanalla määritellyt luokan jäsenkentät ja/tai metodit kuuluvat luokalle eivät luokasta tehdylle olio-instanssille. Tässä tapauksessä määriteltyjä jäseniä/toimintoja voidaan kutsua luokan ulkopuolelta ainoastaan luokan nimen kautta, ei sen olio-instanssin kautta.

Car-luokka esimerkkinä

Alla olevassa Car-luokassa on määritelty MaxSpeed-jäsenmuuttuja staattiseksi static-avainsanalla:


    

Nyt voisimme käyttää Car-luokkaa seuraavasti:


    

Saavuttamamme etu olisi se, että Car-luokassa määritelty MaxSpeed-ominaisuutta ei olisi erikseen alustettu jokaisessa car-luokan instanssissa viemään muistia, vaan car-luokan instanssit käyttäisivät yhtä ja samaa MaxSpeed-ominaisuutta. Huomaa, että yllä olevassa esimerkissä static-ominaisuutta käytetty tavallaan rajaaman auton maksiminopeutta ja ominaisuutta ei muuten käytetty. Staattinen ominaisuus voi olla myös "käytetty" ominaisuus eli sellainen, jonka arvo muuttuisi sovelluksen suorituksen aikana. Tällöin arvon muutos olisi näkyvissä kaikissa ko. luokan toteuttavissa instanssessa.

TemperatureConverter-luokka esimerkkinä

Luokalle voidaan määritellä myös static-määreellä esiteltyjä toimintoja (tai jopa kokonainen luokka voidaan määritellä staattiseksi). Tällöin luokan toimintoja käytetään suoraan luokan nimen kautta. Yleisesti tällaisesta ratkaisusta on hyötyä silloin, kun halutaan esimerkiksi tehdä jotain luokkakirjastoja, jotka suorittavat vain jotain tiettyjä tehtäviä (ja ei ole tarvetta luoda erikseen oliota).


    

Nyt voisimme käyttää TemperatureConverter-luokkaa seuraavasti:


    

C#:ssa luokan alustaja eli konstruktori voi olla myös staattinen. Asiaa ei käsitellä nyt tarkemmin, mutta voit tutustua tilanteeseen täältä: Static Constructors (C# Programming Guide)