Alapfogalmak - Log in
Objektum orientált esettanulmány
Az objektum orientált programozás alapvető tulajdonságait szeretném bemutatni a c++ és a java nyelvben megvalósított objektumok segítségével. Az objektum orientált programozás legfontosabb jellemzői három csoportba foglalhatók össze:
- többértelműség (polimorfizmus)
- elzártság (összezártság)
- öröklődés
A többértelműség azt a lehetőséget takarja, hogy az imperatív programnyelvekkel ellentétben az objektum orientált programnyelvekben nem kell minden függvényünknek, eljárásunknak egyedi névvel rendelkeznie. Az objektum orientált rendszerek a függvényeket és eljárásokat inkább a metódus névvel illetik, a következőkben a metódus megnevezést használom. A metódusok egyedi azonosítására a metódus neve és a paraméter listája szolgál. A paraméterek esetén azok típusa és sorrendje lényeges. Ezt úgy mondjuk, hogy a metódusok szignatúrájának kell eltérőnek lennie. Figyelem a metódus által visszaadott érték nem része a szignatúrának!
c | c++ | java |
---|---|---|
/* különböző neveket kell használni*/ int nagyobbString(char *s, char *t); int nagyobbEgesz(int a, int b); int nagyobbValos(double a, double b); |
// azonos neveket használhatunk int nagyobb(char *s, char *t); int nagyobb(int a, int b); int nagyobb(double a, double b); |
/* azonos neveket használhatunk */ int nagyobb(String s, String t) int nagyobb(int a, int b) int nagyobb(double a, double b) |
A fenti táblázat alapján is feltünően hasonlóak a c, c++ és java nyelven írt sorok. A három nyelv szintaktikája nagy mértékben hasonló, így bármelyiket a elsajátítva már gyorsan megtanulható a másik kettő.
Az összezártság azt fejezi ki, hogy az objektumok tartalmazzák az objektum tulajdonságait leíró adatokat (objektum változók) és a viselkedését megvalósító metódusokat. Az objektumokhoz tartozó metódusok az objektum változókat anélkül elérhetik, hogy azok a metódus paraméter listáján szerepelnének. Ez nagy mértékben lecsökkenti azoknak a programozási hibáknak az esélyét, amikor nem a megfelelő paraméterekkel hívunk meg egy eljárást. Az összezártság mellett az objektum elzárhatja a külvilág elől az egyes elemeit. Így könnyen elkerülhetjük, hogy programhibából kifolyólag kivűlről módosítjuk az objektum tulajdonságait.
Az öröklődés segítségével egyszerűen megvalósítható a már elkészített kódok újrahasznosítása. Az egyes objektumok egymásból származtathatók, a leszármaztatott objektum örökli a szülő objektum tagváltozóit és metódusait. A gyerek objektum újabb tagváltozókat és metódusokat hozhat létre, a szülő objektum metódusait felülbírálhatja.
Gyakran előforduló programozói hiba, hogy elfelejtünk kezdőértéket adni egy változónak. Az objektumok inicializálására az objektum orientált nyelvek egy speciális metódust biztosítanak, melyet konstruktornak neveznek. Egy objektum osztályának több konstruktora lehet, melyeknek a paraméter listájának eltérőnek kell lennie (polimorfizmus). A konstruktoron belül gondoskodhatunk a tagváltozók inicializálásáról. Az egyes objektum osztályokhoz tartozó objektum példányok léthozásakor a megfelelő konstruktort automatikusan végrehajtódik. A c++ és a java nyelvben is a konstruktor neve megegyezik az objektum osztály nevével. Az egyes objektum példányok megszűnésekor egy destruktor automatikusan végrehajtódik, ebben a metódusban van lehetőségünk az objektum példány megszűnése miatt bekövetkező változtatások végrehajtásáról. A destruktor leggyakoribb tevékenysége az objektum példány által dinamikusan lefoglalt memória felszabadítása.
Az objektum orientált és a hagyományos megközelítés összehasonlítására tervezzünk osztályokat kétdimenziós grafikus elemek tárolására és megjelenítésére. Első lépésben pontok, szakaszok és körök kezelésére alkalmas rendszert készítsünk. Tervezzük meg az osztályokat!
A pont osztályt csak azért hozzuk létre, hogy ebből származtassuk további grafikus elemek osztályait és kihasználjuk az öröklődésből származó előnyöket.
pont osztály - bázis osztály azokra a grafikus
elemekre, melyeket egy ponttal lehet jellemezni
tulajdonságok: x, y (pozíció)
metódusok: mozgat, rajzol, töröl (a rajzol és
töröl metódusok semmit sem csinálnak)
pont.mozgat (dx, dy) - mozgat metódus paraméterek dx,
dy (eltolás mértéke)
pont.töröl -objektum képének
törlése
x<-x+dx
y<-y+dy
pont.rajzol - objektum kirajzolása
c++ | java |
---|---|
class pont { protected: double x, y; public: void mozgat(double dx, double dy) { torol(); x += dx; y += dy; rajzol(); } virtual void rajzol() = 0; virtual void torol () = 0; } ; |
public class pont { protected double x, y; public void mozgat(double dx, double dy) { torol(); x += dx; y += dy; rajzol(); } public abstract void torol() {} public abstract void rajzol() {} } |
szimbólum osztály - a pont osztály leszármazottja
(öröklődés)
örökölt tulajdonságok: x, y (pozíció)
új tulajdonságok: típus (milyen alakú szimbólum),
szín
örökölt metódusok: mozgat
felülbírált metódusok: rajzol, töröl
(a bázisosztály metódusainak felülbírálása,
többértelműség)
c++ | java |
---|---|
class szimbolum : pont { protected: int tipus, szin; public: void rajzol() { cout << "szimbólum rajzolás\n"; } void torol() { cout << "szimbólum törlés\n"; } } ; |
class szimbolum extends point { protected int tipus, szin; public void rajzol() { System.out.println("szimbólum rajzolás"); } void torol() { System.out.println("szimbólum törlés"); } } |
A szimbólum osztály a pont osztály mozgat metódusát használhatja! Amennyiben nem bíráljuk felül a bázisosztály valamelyik metódusát, akkor a bázis osztály metódusa hajtódik végre.
kör osztály - a pont osztály leszármazottja
(öröklődés)
örökölt tulajdonságok: x, y (pozíció)
új tulajdonságok: sugár, szín
örökölt metódusok: mozgat
felülbírált metódusok: rajzol, töröl
(a bázisosztály metódusainak felülbírálása,
többértelmûség)
c++ | java |
---|---|
class kor : pont { protected: double sugar; int szin; public: void rajzol() { cout <<kör rajzolás\n" } void torol() { cout << "kör törlés\n" } } ; |
class kor extends point { protected int tipus, szin; public void rajzol() { System.out.println("kör rajzolás"); } void torol() { System.out.println("kör törlés"); } } |
szakasz osztály - nem a pont osztályból
származik, két pont objektumot tartalmaz
tulajdonságok: kezdőpont, végpont (egy-egy pont objektum,
ez nem öröklődés, hanem tartalmazás), szín
metódusok: rajzol, töröl, mozgat
szakasz.mozgat (dx, dy) - szakasz eltolása, a kezdő és
végpont eltolása
szakasz.töröl
kezdőpont.mozgat (dx, dy) - a pont osztály
metódusát használjuk
végpont.mozgat (dx, dy)
szakasz.rajzol
c++ | java |
---|---|
class szakasz { protected: pont kezdoPont, vegPont; int szin; public: void rajzol() { cout <<szakasz rajzolás\n" } void torol() { cout << "szakasz törlés\n" } void mozgat(double dx, double dy) { torol(); kezdoPont.mozgat(dx, dy); vegPont.mozgat(dx, dy); rajzol(); } } ; |
class szakasz { protected pont kezdoPont, vegPont; int szin; public void rajzol() { System.out.println("szakasz rajzolás"); } void torol() { System.out.println("szakasz törlés"); } void mozgat(double dx, double dy) { torol(); kezdoPont.mozgat(dx, dz); vegPont.mozgat(dx, dy); rajzol(); } } |
Nem származtathattuk volna a szakasz osztályt is a pont osztályból? De természetesen úgy is megvalósíthatjuk az osztályunkat.
szakasz1 osztály - a pont osztály leszármazottja
(öröklődés)
örökölt tulajdonságok: x, y (kezdõpont)
új tulajdonságok: dx, dy (szakasz végpontjának
koordinátakülönbségei a kezdőponthoz képest)
örökölt metódusok: mozgat
felülbírált metódusok: rajzol, töröl
(a bázisosztály metódusainak felülbírálása,
többértelműség
c++ | java |
---|---|
class szakasz1 : pont { protected: double dx, dy; int szin; public: void rajzol() { cout <<szakasz rajzolás\n" } void torol() { cout << "szakasz törlés\n" } } ; |
class szakasz1 extends pont { protected double dx, dy; int szin; public void rajzol() { System.out.println("szakasz rajzolás"); } void torol() { System.out.println("szakasz törlés"); } } |
Miért a koordinátakülönbségeket tároljuk és nem a végpont koordinátáit? Azért mert így a mozgat metódust nem kell újra elkészíteni ehhez az osztályhoz is! Ez az utóbbi megvalósítása a szakasz objektumnak más szempontból is kedvezőbb. Ha az objektum struktúránkban található egy közös bázis osztály (esetünkben a pont), akkor az összes objektumra érvényes, átvihető metódusokat ehhez a bázis osztályhoz rendelhetjük.
Ezt a primitív rendszert tételezzük fel, hogy megvalósítja
valaki. Később viszont tökéletesíteni
szeretnénk a rendszerünket. Próbáljuk meg a már
meglévõ elemeket hasznosítani.
Adjunk lehetőséget elforgatható szimbólumok
kezelésére.
forgatható szimbólum osztály - a szimbólum
osztály leszármazottja
örökölt tulajdonságok: x, y (pozíció),
típus, szín
új tulajdonságok: forgatási szög
örökölt metódusok: mozgat
felülbírált metódusok: rajzol, töröl
c++ | java |
---|---|
class forgathatoSzimbolum : szimbolum { protected: double szog; public: void rajzol() { cout << "forgatható szimbólum rajzolás\n" } void torol() { cout << "forgatható szimbólum törlés\n" } } ; |
class forgathatoSzimbolum : szimbolum { protected double szog; public void rajzol() { System.out.println("forgatható szimbólum rajzolás"); } void torol() { System.out.println("forgatható szimbólum törlés"); } } |
Természetesen a grafikus, térinformatikai rendszerek sokkal
összetettebb objektum struktúrával rendelkeznek. Ez
viszont azt is jelenti, hogy sokkal több lehetőség van
(jó tervezés esetén), hogy kihasználjuk az
öröklõdésbõl származó előnyöket.
A meglévő programrészeket újrahasznosíthatjuk,
függetlenül attól, hogy ki és mikor készítette
azt..