Alapfogalmak - Belépés

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!

cc++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..
 

Utolsó módosítás: 2017. március 9., csütörtök, 19:07