2. Objektumorientált paradigma

Az objektumorientált programozás alapfogalmaival korábban már bizonyára minden olvasó találkozott. A téma rendkívüli fontossága miatt egy rövid bevezetést is olvashatnak ebben a fejezetben.

A jegyzet példái általában elég egyszerűek, de érdemes minél előbb megismerkedni egy olyan jelölésmóddal, amivel az objektumorientált programunkat előre megtervezhetjük. Leíró eszközként a leginkább elterjedt UML (Unified Modeling Language) jelöléseivel fog találkozni a jegyzetben a tisztelt olvasó.

2.1. Az objektum

Az objektumok az objektumorientált technológia alapjai. Néhány példa a hétköznapi életből: kutya, asztal, tv, bicikli. Ezek a valódi objektumok két jellemzővel rendelkeznek: állapottal és viselkedéssel. Például a kutya állapotát a neve, színe, fajtája, éhessége stb. jellemzi, viselkedése az ugatás, evés, csaholás, farok-csóválás stb. lehet. A bicikli állapotát a sebességfokozat, a pillanatnyi sebesség, viselkedését a gyorsulás, fékezés, sebességváltás adhatja.

UML objektum diagram

A programbeli objektumok modelljei a valódi objektumoknak. Az objektum állapotát egy vagy több változóval, a viselkedését az objektumhoz rendelt metódussal (függvénnyel) írjuk le.

Az objektum változókból és kapcsolódó metódusokból felépített egység.

A valós élet objektumait leírhatjuk program objektumokkal. Ha szükség van arra, hogy valódi kutyákat ábrázoljunk egy animációs programban, akkor használhatunk program objektumokat az elvont fogalmak modellezésére. Például egy hétköznapi eseményt modellezhet egy billentyűleütés vagy egérkattintás.

Egy biciklit modellező objektum változókkal írja le a pillanatnyi állapotot: a sebesség 18 km/h, és a sebességfokozat 5-ös. Ezeket a változókat példányváltozóknak nevezzük, mert ezek egy konkrét bicikli állapotát írják le. Az objektumorientált terminológiában egy önálló objektumot példánynak is nevezünk. A következő ábra bemutat egy biciklit modellező objektumot az UML objektumdiagramja (Object diagram) segítségével.

A bicikli tud fékezni, sebességfokozatot váltani is. Ezeket a metódusokat példánymetódusoknak hívjuk, mivel egy konkrét bicikli (példány) állapotában képesek változást elérni.

Az objektum tulajdonságait szokás a külvilágtól elrejteni, és csak a metódusokon keresztül befolyásolni.

Az objektum változók becsomagolását, védőőrizetbe helyezését egységbezárásnak nevezzük.

Időnként – gyakorlati megfontolásból – egy objektum megmutat néhány változóját és elrejti néhány metódusát. A Java nyelvben az objektum meg tudja határozni, hogy négy hozzáférési szint közül melyiket választja az egyes változók és metódusok számára. A hozzáférési szint határozza meg, hogy más objektumok és osztályok hozzá tudjanak-e férni az egyes változókhoz és objektumokhoz.

Az egységbezárás tiszta alkalmazása esetén két egyszerű, de nagyon hasznos előnye lesz a szoftverfejlesztőnek:

  • Modularitás: Az objektum forráskódja független marad más objektumok forráskódjától. Ezen kívül az objektum könnyen tud illeszkedni a rendszer különböző részeihez.
  • Információ elrejtés: Az objektum a publikus interfészén keresztül nyújt kommunikációs lehetőséget a többi objektum felé. Az objektum gondoskodik a saját adatairól, és csak a metódusain keresztül ad változtatási lehetőséget a külső objektumoknak. A külső objektumoknak igazából nem is kell tudnia arról, hogy az objektum állapota milyen belső változókkal van reprezentálva, csak a kívánt viselkedést kell kérnie a metódusokon keresztül.

2.2. Az üzenet

Amíg csak egy objektumunk van, addig nem sok haszna van a programnak. Általában egy objektum csak egy kis részét jelenti egy nagyobb alkalmazásnak. Ezért kölcsönhatás van az objektumok között. A biciklink egy összetett szerkezet, magában mégis használhatatlan, kapcsolatba kell kerülnie más objektummal, pl. velünk a pedálon keresztül.

UML interakció diagram

A program objektumok hatnak egymásra és kommunikálnak egymással üzeneteken keresztül. Amikor az A objektum meghívja a B objektum egy metódusát, tulajdonképpen egy üzenetet küld neki. Ezt az UML szekvencia diagramja a következő módon ábrázolja (az idő fentről lefelé halad):

Néha a fogadó objektum több információt igényel, hogy pontosan tudja, mi a dolga. Például amikor sebességet váltunk a biciklin, megadjuk a kívánt sebességváltás irányát is. Ezt az információt paraméterként adjuk az üzenethez.

Az üzenet három része összefoglalva:

  • Melyik objektum az üzenet címzettje
  • A végrehajtandó metódus neve
  • Az esetleges paraméterek

Ez a három összetevő elegendő, hogy a meghívott objektum végrehajtsa a kívánt metódust. Az üzenetek két fontos előnnyel járnak:

  • Egy objektum viselkedését meghatározzák a metódusai, üzenetküldéssel megvalósítható az összes lehetséges kapcsolat két objektum között.
  • Nem szükséges, hogy az objektumok ugyanabban a folyamatban, vagy akár ugyanazon gépen legyenek, az üzenetküldés és fogadás ettől függetlenül lehetséges.

Üzenetek a gyakorlatban

Az elméleti objektumorientált szemléletben megkülönböztetünk aszinkron és szinkron üzenetküldéses rendszert. Bár a hétköznapi modellt az aszinkron megközelítés jellemzi, gyakorlati, megvalósíthatósági okokból a programnyelvek többnyire a szinkron üzenetküldéses modellen alapulnak.

2.3. Az osztály

A valódi világban gyakran sok objektummal találkozunk ugyanabból a fajtából. Például a biciklink nagyon sok más biciklire jelentősen hasonlít. Az objektumorientált szóhasználatban azt mondjuk, hogy egy konkrét bicikli a biciklik osztályának egy példánya. A biciklik rendelkeznek állapottal (aktuális sebességfokozat, fordulatszám stb.) és viselkedéssel (sebességváltás, fékezés). Ennek ellenére minden bicikli konkrét állapota független az összes többi bicikli állapotától.

UML osztálydiagram

Osztályozásnak nevezzük azt a folyamatot, amelynek során a hasonló objektumokat közös csoportokba, más néven osztályokba soroljuk.

Amikor a biciklik készülnek, a gyártók nyereséget szeretnének előállítani, ezért a biciklik nagy mennyiségben, közös tervrajz alapján sorozatgyártásban készülnek. Nagyon rossz lenne a hatásfok, ha minden biciklihez egyedi tervrajzot kellene készíteni.

Az objektumorientált programokban is hasonló a helyzet: közös tervezésre ad lehetőséget, hogy sok objektum hasonló jellemzőkkel rendelkezik: téglalapok, alkalmazottak, videofelvételek, stb. A kerékpárgyártókhoz hasonlóan nekünk is előnyös az, ha sok hasonló objektumot közös tervrajz alapján készíthetünk el. Az objektumok tervrajzait hívjuk osztályoknak.

Az osztály bizonyos fajta objektumok közös változóit és metódusait leíró tervrajz.

A bicikli osztály legszükségesebb példányváltozói az aktuális sebesség és a sebességfokozat lehetnek. Az osztály tartalmazza a példánymetódusokat is: a sebességváltást és a fékezést, ahogy a következő UML osztálydiagramon (Class diagram) látszik:

A következő kód az így megtervezett osztály kódját tartalmazza:

class Bicycle {
       int cadence = 0;
       int speed = 0;
       int gear = 1;
       void changeCadence(int newValue) {
            cadence = newValue;
       }
       void changeGear(int newValue) {
            gear = newValue;
       }
       void speedUp(int increment) {
            speed = speed + increment;  
       }
       void applyBrakes(int decrement) {
            speed = speed – decrement;
       }
       void printStates() {
            System.out.println("cadence:"+cadence+" speed:"+speed+" gear:"+gear);
       }
}

Miután létrehoztuk a Bicikli osztályt, az osztály alapján akármennyi bicikli objektumot létre tudunk hozni. Amikor példányosítunk egy osztályból, a futtatórendszer elegendő memóriát foglal az objektum példányváltozóinak. Minden példány kap egy másolatot a definiált változókról:

Nézzük meg egy bicikliket példányosító kódot:

class BicycleDemo {
     public static void main(String[] args) {
          // Create two different Bicycle objects
          Bicycle bike1 = new Bicycle();
          Bicycle bike2 = new Bicycle();
          // Invoke methods on those objects
          bike1.changeCadence(50);
          bike1.speedUp(10);
          bike1.changeGear(2);
          bike1.printStates();
          bike2.changeCadence(50);
          bike2.speedUp(10);
          bike2.changeGear(2);
          bike2.changeCadence(40);
          bike2.speedUp(10);
          bike2.changeGear(3);
          bike2.printStates();
     }
}

A példányváltozók mellett az osztályok definiálhatnak osztályváltozókat is. Az osztályváltozók az összes objektumpéldány számára megosztott információkat tartalmaznak. Például képzeljük el, hogy az összes kerékpár ugyanannyi sebességfokozattal rendelkezik. Ebben az esetben felesleges példányváltozót alkalmazni, minden példány ugyanazt a másolatot tárolná. Ilyenkor osztályváltozóban érdemes az adatot tárolni, amit minden példány el tud érni. Ha egy objektum megváltoztatja az értékét, az összes objektum számára is megváltozik.

Az osztálynak lehet osztálymetódusa is.

Az objektumok használatának előnye a modularitás és az információelrejtés. Az osztályok használatának előnye az újrafelhasználhatóság. A bicikligyárak újra és újra fel tudják használni a gyártás során az egyszer elkészített tervrajzokat. A programozók ugyanazokat az osztályokat, ugyanazokat a kódokat újra és újra felhasználják a példányosítás során.

2.4. Az öröklődés

Az objektumorientált rendszerekben egyes objektumok között további összefüggéseket figyelhetünk meg. Bizonyos feltételeknek megfelelő objektumok egy másik osztályba sorolhatók. Például a hegyi vagy éppen a városi biciklik a biciklik speciális fajtái. Az objektumorientált szóhasználatban ezeket leszármazott osztálynak nevezzük. Hasonlóan, a bicikli osztály ősosztálya (szülő osztálya, bázisosztálya) a városi biciklik osztályának. Ezt az összefüggést mutatja a következő ábra:

Öröklődés

Az objektumorientált tervezés folyamán használt általánosítás és specializálás fogalmak az osztályhierarchia kialakítása során használatosak. Az őstől a gyermek felé speciálisabb osztályokat látunk, visszafele pedig egyre általánosabbakat.

Minden gyermekosztály örökli az ősosztály állapotát és a metódusait, de nincs ezekre korlátozva. A gyermekosztályok hozzáadhatnak változókat és metódusokat ahhoz, amit az ősosztálytól örökölt. A gyermekosztályok felül tudják írni az örökölt metódusokat, vagy speciálisabb megvalósítást tud adni azoknak.

Például a Hegyi bicikli a Bicikli leszármazottja:

class MountainBike extends Bicycle {
     // új adattagok és metódusok helye
}

Az öröklődésnél nem vagyunk behatárolva egy szintre. Az öröklési fa, vagy más néven az osztályhierarchia több szintű öröklést is lehetővé tesz, bár egy átlagos felhasználói program esetén legtöbbször 4-5 szint elegendő.

Az öröklődés a következő előnyökkel jár:

  • A leszármazott osztályok tudják specializálni az ősosztálytól örökölt viselkedést. Az öröklődés segítségével az egyes osztályokat újra fel lehet használni.
  • A programozók meg tudnak valósítani olyan viselkedéseket, amelyek az ősosztályban még nem voltak konkrétan leírva. (Az ilyen osztályokat absztrakt, elvont osztályoknak nevezzük.) Az absztrakt ősosztályok csak részben valósítják meg a szükséges viselkedéseket, és akár más programozók fogják azt a leszármazottakban megvalósítani.

Megjegyzés: Az objektumorientált szemlélet megismerése után sok fejlesztő számára erős a kísértés, hogy olyankor is az öröklődést alkalmazza, amikor inkább más technikákat (pl. kompozíció, aggregáció) érdemes alkalmazni.

Javában az Object osztály az osztályhierarchia legfelső eleme, minden más osztály belőle származik (közvetlenül vagy közvetve). Az Object típusú referencia bármilyen objektumra tud hivatkozni.

Az Object osztálynak olyan megosztott viselkedései (metódusai) vannak, amelyek lehetővé teszik a Java VM-en való futást. Például minden osztály örökli a toString metódust, hogy az objektum sztringként is megmutatható legyen.

2.5. Publikus interfész

Általánosságban egy eszköznek vagy rendszernek szokás az interfészéről beszélni: azt írja le, hogy külső dolgok hogyan tudnak kapcsolódni hozzá. Ilyen értelemben két magyar ember között egy interfész a magyar nyelv.

Egy tetszőleges osztály esetén tehát a publikus interfész alatt az osztály kívülről is látható (publikus) felületét értjük. (Ez többnyire a publikus konstruktorokra és metódusokra korlátozódik.) Az üzenetküldés fogalmára visszautalva az osztály publikus interfésze azt határozza meg, hogy más objektumok milyen üzenetet küldhetnek az objektumnak, illetve milyen módon hozhatnak létre az osztálynak egy példányát.

Java interfész

Érdemes itt megemlíteni, hogy ez az elméleti fogalom nem egyezik meg a Java interfész fogalmával. A Java nyelven belül az interfész egy típus, mint ahogy az osztály is típus. Az osztályhoz hasonlóan az interfész is definiál metódusokat, de attól eltérően soha nem valósít meg metódust. Az interfészt megvalósító osztály fogja annak metódusait megvalósítani.

Az interfészek hasznosak a következő esetekben:

  • Hasonlóságok megfogalmazása anélkül, hogy mesterkélt osztályhierarchiát építenénk fel
  • Olyan metódusok definiálása, amelyeket több osztályban meg kell valósítani
  • Többszörös öröklődés modellezése a más nyelvekből ismert veszélyek nélkül

2.6. Ellenőrző kérdések

  • Mi az objektum?
  • Mi az üzenet? Hogyan valósul meg a Java nyelvben?
  • Mi az osztály?
  • Mi az információ-elrejtés?
  • Mit értünk egy osztály publikus interfészén?
  • Mi az Object osztály szerepe?
  • Mitől objektumorientált egy program?

Igaz vagy hamis? Indokolja!

  • Az absztrakció az objektumok közötti hasonlóságok figyelése, összegyűjtése.
  • Az osztályozás a világ objektumainak rendszerezése.
  • Az általánosítás a világ objektumainak leegyszerűsítése.
  • A specializálás egy szűkebb kategória meghatározása az objektumok különbözősége alapján.
  • Az objektumorientált program egymással kommunikáló objektumok összessége, ahol minden objektumnak megvan a jól meghatározott feladatköre.
  • Az objektum példányokat tulajdonságaik és viselkedésük alapján osztályokba soroljuk.
  • Csak akkor küldhető üzenet egy objektumnak, ha a küldő és a fogadó objektum kapcsolatban állnak egymással.
  • Ha két objektum állapota megegyezik, akkor a két objektum azonos.
  • Az osztály meghatározza objektumainak viselkedését.
  • Ha két objektum ugyanahhoz az osztályhoz tartozik, és ugyanaz az állapota, akkor ugyanarra az üzenetre ugyanúgy reagál.

Gyakorló feladat

Modellezze egy nyelviskola tanfolyam-szervezési feladatkörét!

  • Kik vesznek részt a folyamatban?
  • Hogyan osztályozhatjuk őket?
  • Milyen öröklési kapcsolatok vannak az osztályok között?
  • Milyen műveleteket képesek végezni az objektumok?

Modellezze egy cég (pl. egy 5-10 fős Kft.) tevékenységét!

  • A munka során mik (és kik) tekinthetők objektumnak?
  • Milyen jellemzőkkel és viselkedési lehetőségekkel (itt speciálisabban munkaképességekkel) rendelkeznek?
  • Van-e osztályozási lehetőség az objektumok között?