11. Az OOP alapjai

Az objektum orientált programozás (OOP) azért jött létre, hogy az 1960-as években egyre összetettebbé és bonyolultabbá váló programokban csökkentsék a meglévő hibákat. A használt adatszerkezetekben több alkalommal szerepeltek szöveges adatok, dátumok és egyéb nem numerikus adatok. A szoftverek fejlesztésén munkacsoportok kezdtek dolgozni. Szükség volt olyan programozási elméleti megoldásra, amelyben a kezelendő adatok és az azokat kezelő kód szorosan összetartozik, továbbá a munkacsoportokban a különböző fejlesztők egymás kódjaiból csak a szükséges részeket láthatták és használhatták fel.

Osztály - Class

Az osztály egy összetett adattípus és leginkább a struktúrákhoz hasonlítható. Több, mint adattípus, mert nem csak adatokat tárolhatunk egy osztályban, hanem az osztály szerves részét képezik az adatokat feldolgozó kódok is. Az osztály definíciójakor az adatszerkezet és az adatok feldolgozásához szükséges kódot hozzuk létre.

Objektum

Amikor egy osztályból objektumot hozunk létre, akkor ezt példányosításnak hívják. Ettől a pillanattól kezdve adhatunk neki értéket, részt vehet különböző műveletekben, tehát használhatjuk. A példányosítás a program futtatható részében történik.

Adattagok vagy tulajdonságok (property)

Az osztály valamilyen szempontból több együtt tárolandó és feldolgozandó adat összessége. Például ha egy kutya állapotát leíró tulajdonságokat adattagoknak is hívhatjuk. Az adattagok önmagukban csak tárolják egy kutya tulajdonságait, de azokat nem változtathatják meg.

  • nev
  • születési időpontja
  • fajta
  • Nem
  • jóllakottság

Metódusok - tagfüggvények

Az olyan függvényeket, amelyek egy osztályban lévő tulajdonságokat módosítanak metódusoknak hívjuk.

A metódusok tulajdonképpen függvények. Van paraméterlistájuk és lehetnek visszatérési értékeik illetve ha egy metódusnak nincsen visszatérési értéke, akkor azt a void kulcsszóval jelöljük.

A fenti tulajdonságok változásanak kezelése az adatokon való változtatást jelentik. Például óránként a jóllakottság mértéke 100-ról csökkenhet 0-ig. Ha az érték 0, akkor a kutya nagyon éhes, ha 100, akkor teljesen jóllakott. Ha szaladgál, akkor gyorsabban csökken, ha fekszik és alszik, akkor lassabban. Az osztályba kellene egy olyan kód, ami óránként csökkenti az éhség szintjét. Ha fut a kutya, akkor pedig gyorsabban csökken a jóllakottság szintje. Kell akkor olyan kód is, amely megeteti a kutyát.

Minden osztálynak van két speciális metódusa, amelyet a rendszer alapesetben biztosít még akkor is, ha a fejlesztő  hozza létre.

  • Konstruktor: Olyan metódus, amely akkor fut le, amikor az osztályt példányosítjuk, vagyis a memóriában létrehozzuk a szükséges memóriaterületet.
  • Destruktor: Ha egy objektum megszűnik, akkor a destruktor felszabadítja azokat az erőforrásokat, amelyeket a létrehozás és a használat során a program lefoglalt.

Láthatóság

Az objektum-orientált programozás egyik alapelve az, hogy az osztályok adattagjait és metódusait csak a szükséges mértékben érhessék el külső eljárások, metódusok. Más fejlesztők csak azt lássák, amire feltétlenül szükségük van. Ezt a láthatóság szabályozza.

  • public:  Ha egy adattag vagy metódus a program bármelyik részéből elérhető.
  • private: Csakis az osztályon belül érhető el az osztály más metódusaiból
  • protected: Csakis az osztályon belülről érhető el, de a leszármazott osztályok módosíthatják (leszármazást mindjárt elmondom)

Egységbezárás (Encapsulation) elve

A láthatósági szabályokat és a metódusok paraméterlistáit, illetve visszatérései típusait együtt az osztály felületének (interface) hívjuk. Az egységbezárás elve azt jelenti, hogy az osztályok belső szerkezetét a fejlesztők egészen addig nyugodtan változtathatják, ameddig az osztály felülete változatlan marad. Ilyen módon más fejlesztők, illetve más alkalmazásoknak a kód változására nem kell figyelniük, ameddig az interface nem változik.

Öröklődés - származtatás

Minden OOP nyelv tartalmaz úgynevezett ős osztályokat. Az osztályok a nyelv láthatatlan részei és mindig használhatók. Az ős osztályok tartalmazzák azokat a szükséges konstruktorokat, amelyek a példányosítás során a szükséges memóriát lefoglalják, illetve megszűnés esetén felszabadítják a lefoglalt memóriát.

Ha létrehozunk egy osztályt C# nyelven, akkor az ős osztály egy leszármazottját hozzuk létre. Ez azt jelenti, hogy az ős osztály minden meglévő adattagja és metódusa a leszármazott osztályban is használható. A leszármazást mi is megvalósíthatjuk saját programjainkban.

{Ős osztály} => {Leszármazott osztály}
(szülő)            (gyerek) 

Példa

Ha létrehozzuk például kutya nevű osztályt, majd utána létrehozzuk a foxterrier nevű másik osztályt, amely a kutya osztály leszármazottja, akkor a kutya osztályban azokat a tulajdonságokat fogalmazzuk meg, amely minden kutyára jellemzőek, a foxterrierben pedig hozzá vesszük azokat a tulajdonságokat, amely csak erre a fajtára jellemzők.

Ilyenkor a kutya osztály őse a foxterrier osztálynak vagy másként szólva a foxterrier osztály leszármazottja a kutya osztálynak.

Másik példa a geometriai formák esetén.

A pont nevű osztály tartalmaz három tulajdonságot: x, y koordináták és a színe. Legyen egy rajzol metódusa, amely megadott színnel az x,y koordinátába megjeleníti a pontot.

A kör nevű osztály leszármazottja a  pont osztálynak, mert a körnek van középpontja, ami lényegében a pont osztálynak felel meg, ugyanakkor plusz tulajdonsága a sugara. A rajzol metódusa ugyanakkor nem lehet az eredeti kör metódusa, hiszen a körvonal megrajzolása sokkal több tevékenység, bár a neve lehet ugyanaz.

A szakasz osztályt nem érdemes a pont osztály leszármazottjának tekinteni. Jobb megoldás, ha külön ős osztályt definiálunk szakasz néven.

A szakasz osztály és a pont osztály további leszármazottja lehet a szabályos sokszög. A szabályos sokszögnek is van középpontja, ugyanakkor szakaszok alkotják az oldalait. Ez tehát azt jelenti, hogy célszerűen a szabályos sokszögnek ős osztálya a pont osztály és ős osztálya lehet a szakasz osztály is.

Összefoglalva: A C#-ban egy osztálynak több ős osztálya lehet és minden osztálynak tetszőleges számú leszármazottja lehet. Szokták az ősöket szülő osztálynak és a leszármazottakat gyerek osztálynak hívni.

{Ős osztály} => {Emlős} 
                  => {Kutya}
                        => {Német juhász}
                        => {Foxterrier}
                  => {Macska}

Túlterhelés

Amikor azonos nevű, de eltérú paraméterezésű metódusokat hozunk létre, akkor ezt túlterhelésnek hívjuk.

Gyakran előfordul, hogy ugyanazt a műveletet egy osztályon belül különböző típusú és paraméterezésű adatokkal akarom elvégezni. Mivel a metódus definiálásakor kötelező megadni a paraméterlistát, ezért az ugyanolyan nevű, de eltérő paraméterezésű metódusokat a fordító meg tudja különböztetni,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace kutyusok
  class kutya
  {
    string  nev;
    int     szulido;
    boolean nem;
    int     jollakottsag = 0;

    public void etetes(float x){
        etetes( (int) x);
    }

    public void etetes(int x){
      if(jollakottsag < 100 )
      {
         jollakottsag += x;
         Console.WriteLine("Megette a kaját");
      }else{
         Console.WriteLine("Nem ette meg, mert már jóllakott")
      }
    }

    public void egyre_ehesebb(){
      jollakottsag--;
      if(jollakottsag <1){
        Console.WriteLine("Baromi éhes!!!!");
      }
    }

    public void egyre_ehesebb(int perc){
      jollakottsag -=perc;
      if(jollakottsag <1){
        Console.WriteLine("Baromi éhes!!!!");
      }
    }

    public szaladgal(int perc){
        egyre_ehesebb(perc)
    }
  }

  //A kutya osztály leszármazottja a foxterrier
  class foxterrier: kutya
     public int szor_hossza;
  }

  // Főprogram
  class program{
    static void Main(string[] args){
      kutya k = new kutya();
      k.etetes(99);
      for(int i=0;i<50;i++){
         k.szaladgal(2);
      }
    }
  }

A következő fejezetekben látunk néhány példát az osztályok és objektumok használatára.